<分区>
<分区>
id getBlockArr() {
NSInteger val = 10;
return [[NSArray alloc] initWithObjects:^{ NSLog(@"value: %ld", val);},^{ NSLog(@"value: %ld", val);},^{ NSLog(@"value: %ld", val);}, nil];
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
id arr = getBlockArr();
void(^blk)(void) = [arr objectAtIndex:0];
blk();
}
return 0;
}
根据Apple的文档,当blk
被释放时,它会崩溃,但是在我运行此代码后,我看到*value: 10*
记录到控制台。然后应用程序崩溃。我在arr
处设置了断点。
索引0处的 block 是NSMallocBlock
,它说是复制到堆,但是索引1和索引2处的 block 是错误的,所以这是怎么回事?
最佳答案
这似乎与 initWithObjects 签名有关:
- (instancetype)initWithObjects:(ObjectType)firstObj, ...;
只有第一个参数是必需的,其余的都是可选的。这暗示它可能会受到不同的对待。
通常,如果您声明 block 变量并捕获变量,它们将变为 __ NSMallocBlock__
:
dispatch_block_t b1 = ^{ NSLog(@"value: %ld", val); };
dispatch_block_t b2 = ^{ NSLog(@"value: %ld", val); };
dispatch_block_t b3 = ^{ NSLog(@"value: %ld", val); };
如果你不声明变量,而是在函数内部传递一个 block ,它就变成了一个__NSStackBlock__
:
void f(dispatch_block_t b) {
b();
}
void g() {
NSInteger val = 10;
f(^{ NSLog(@"value1: %ld", val); });
}
区别类似于 @escaping
而不是 Swift 中的 @escaping。
__NSStackBlock__
block 在栈销毁后被销毁,函数返回后尝试访问内存时,访问会崩溃。
请注意,新语法使所有 3 个 block 成为 __NSMallocBlock__
并且不会崩溃:
return @[
^{ NSLog(@"value1: %ld", val); },
^{ NSLog(@"value1: %ld", val); },
^{ NSLog(@"value1: %ld", val); }
];
我敢打赌,这个怪癖是由编译器默认将所有可选 C(省略号) block 参数视为 __NSStackBlock__
的方式引起的。
关于ios - 当我在数组中创建一些 block 时,为什么索引 0 不应该被复制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50238071/