当添加到容器(NSDictionary,NSArray)时,您能帮助我理解块类型吗? [英] Could you help me to understand block types when added to containers (NSDictionary, NSArray)?
问题描述
通常,块可以是3种类型:NSGlobalBlock,NSStackBlock,NSMallocBlock.让我们以以下示例为例:
Normally blocks can be of 3 types: NSGlobalBlock, NSStackBlock, NSMallocBlock. Lets take the following example:
void (^aBlock)(NSString *someString) = ^(NSString *someString){
NSLog(@"Block was executed. %@", someString);
};
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:aBlock forKey:@"aBlock"];
因为如果我做 po字典,我会得到
Because aBlock doesn't capture surrounding scope if I do po dictionary I get
aBlock =< NSGlobalBlock :0x165dde60>,这是正确的
aBlock = <NSGlobalBlock:0x165dde60> and this is correct
如果我再这样做:
NSString *string = @"Test";
void (^aBlock)(NSString *someString) = ^(NSString *someString){
NSLog(@"Block was executed. %@ %@", someString, string);
};
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:aBlock forKey:@"aBlock"];
然后是 po字典,我得到:
aBlock =< NSMallocBlock :0x165dde60> 这就是令我困惑的
aBlock = <NSMallocBlock:0x165dde60> and this is what confuses me
这不是 NSStackBlock ,而是在执行以下操作时仅成为 NSMallocBlock :
Shouldn't this be a NSStackBlock and only become a NSMallocBlock when I do:
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:[aBlock copy] forKey:@"aBlock"];
我在使用ARC的iOS 7.1上,据我所知,在向下传递堆栈时,默认情况下不应在ARC中复制块,而应仅在向上传递堆栈(从函数返回)时才复制它们.
I am on iOS 7.1 using ARC and as far as I know blocks should not be copied by default in ARC when passed down the stack and they should be copied only when passed up the stack (returning from a function).
我在这里想念什么?
推荐答案
在这些行上,字典中块对象的类型已经是NSMallocBlock,而不是通过NSDictionary + dictionaryWithObject:forKey:方法复制的.
The type of the block object in the dictionary was already NSMallocBlock on these lines, not from copied by NSDictionary +dictionaryWithObject:forKey: method.
void (^aBlock)(NSString *someString) = ^(NSString *someString){
NSLog(@"Block was executed. %@ %@", someString, string);
};
在ARC编译环境下,默认情况下,此aBlock变量为__strong.
This aBlock variable is __strong by the default under ARC compilation environment.
__strong void (^aBlock)(NSString *someString) = ^(NSString *someString){
...
因此,块对象由aBlock变量保留.实际上,根据LLVM源代码,编译器发出了 retain 代码,用于将对象存储到该行的__strong变量中.
So the block object was retained by the aBlock variable. Actually, according to LLVM source code, the compiler emitted retain code for storing the object into __strong variable on the line.
- https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L2091
- https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L2109
- https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L1920
- https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L1944
- https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L2091
- https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L2109
- https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L1920
- https://github.com/llvm-mirror/clang/blob/master/lib/CodeGen/CGObjC.cpp#L1944
EmitARCRetainBlock:
EmitARCRetainBlock:
llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value, bool mandatory) {
llvm::Value *result = emitARCValueOperation(*this, value,
CGM.getARCEntrypoints().objc_retainBlock, "objc_retainBlock");
此 objc_retainBlock 是objc4中的运行时函数.
This objc_retainBlock is a runtime function in objc4.
http://opensource.apple.com/source/objc4/objc4-551.1/runtime/NSObject.mm
id objc_retainBlock(id x) {
return (id)_Block_copy(x);
}
因此,此_Block_copy将块对象从堆栈复制到堆.
Thus, the block object was copied from stack to heap by this _Block_copy.
除此之外,您还可以使用 __ weak 来查看块对象的 __ NSStackBlock __ 类型.
In addition to this, you can see __NSStackBlock__ type for the block object using __weak.
__weak void (^aBlock)(NSString *someString) = ^(NSString *someString){
NSLog(@"Block was executed. %@ %@", someString, string);
};
在这种情况下,aBlock变量未保留该块对象,并且该块对象不是普通的Objective-C对象,因此该块对象可以存在于堆栈中.是的,它是 __ NSStackBlock __ 对象.在存储到NSMutableDictionary中之前,可能需要先调用 copy 或 Block_copy .
In this case, the block object was not retained by the aBlock variable, and the block object is not an ordinary Objective-C object, so the block object can exist on stack. Yes, it is __NSStackBlock__ object. You may need to call copy or Block_copy for it ahead of storing into NSMutableDictionary.
这篇关于当添加到容器(NSDictionary,NSArray)时,您能帮助我理解块类型吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!