ios - 当我在数组中创建一些 block 时,为什么索引 0 不应该被复制?

标签 ios objective-c copy automatic-ref-counting block

<分区>

    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处设置了断点。

a busy cat 索引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__ 的方式引起的。

有趣的阅读:https://clang.llvm.org/docs/Block-ABI-Apple.html

关于ios - 当我在数组中创建一些 block 时,为什么索引 0 不应该被复制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50238071/

上一篇:ios - 如何在 iOS 的 UILabel 上将可见文本作为字符串获取?

下一篇:ios - Apple 如何规定哪些类应该分解为一个类的协议(protocol)接口(interface)?

相关文章:

c++ - 从文件的特定部分(复制到文档目录中)初始化 NSInputStream?

xml - 如何复制一个元素(文本字符串)的内容并附加到另一个元素的内容? (XML)

sql - 将表从一个数据库复制到 SQL Server 中的另一个数据库

python - 递归地创建子类的副本?

ios - Swift 中开关盒的详尽条件

html - iOS 上的列表问题

ios - #警告: C-style for statement is deprecated and will be removed in a future version of Swift

objective-c - 最好在转换之前检查对象的类别吗?

ios - 如何创建一个在不活动后返回到先前状态的 iOS webapp?

ios - 尝试重新加载部分时断言失败错误