Objective-c block 生命周期 ARC

标签 objective-c objective-c-blocks

我对 ARC 下 block 的生命周期感到困惑。我已经编写了一个单元测试来演示让我感到困惑的地方。

- (void)testBlock {
    NSObject *testObject = [[NSObject alloc] init];
    CompletionBlock testBlock = ^{ NSLog(@"%@", testObject); };
    XCTAssertNotNil(testObject, @"testObject should not be nil");

    __weak NSObject *weakTestObject = testObject;
    @autoreleasepool {
        testObject = nil;
    }
    XCTAssertNotNil(weakTestObject, @"testObject should be retained by testBlock");

    @autoreleasepool {
        testBlock = nil;
    }
    //THIS IS THE FAILING TEST CASE
    XCTAssertNil(weakTestObject, @"testObject should have been released when testBlock was released");
}

我猜测这种行为与 block 在堆栈/堆上的存储方式有关。

更新!

将 block 设置为 nil 不会像我预期的那样释放 block ,因为它在堆栈上并且在超出范围之前不会被释放。强制 block 超出范围修复了我的测试。更新了下面的代码。

- (void)testBlock {
    NSObject *testObject = [[NSObject alloc] init];
    __weak NSObject *weakTestObject = testObject;

    @autoreleasepool {
        CompletionBlock testBlock = ^{ NSLog(@"%@", testObject); };
        XCTAssertNotNil(testBlock, @"testBlock should not be nil");
        XCTAssertNotNil(testObject, @"testObject should not be nil");

        testObject = nil;
        XCTAssertNotNil(weakTestObject, @"testObject should be retained by testBlock");
        //testBlock goes out of scope here
    }
    XCTAssertNil(weakTestObject, @"testObject should have been released when testBlock was released");
}

最佳答案

block 是在堆栈上创建的,只有在作用域退出时才会被销毁,这很像带有析构函数的 C++ 堆栈分配对象。这些 block 免于引用计数并将忽略 保留/释放 消息。只有在被复制后(通过 Block_copy() 函数或 copy 消息)它们才成为可以保留和释放的普通堆分配对象。

在您的示例中,如果您将断言之前的所有代码包装在额外的大括号 { } 中,断言将开始工作,以便断言在 block 变量的范围之后执行结束。

关于Objective-c block 生命周期 ARC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24093802/

相关文章:

iphone - 以编程方式将自动布局约束添加到恒定宽度和高度的 subview

objective-c - block 被释放时的回调

ios - 如何在 Swift 中正确地将 block 处理程序传递给此函数?

ios - NSBlock 的访问限定符是复制还是弱还是强?

iphone - 未调用完成 block 。如何检查有效性?

ios - Cocoapods 更新后未调用 Objective-C block

objective-c - 我必须在 iOS 的 Objective-C 中保留 block 吗?

ios - 在哪里设置 subview 的图层属性?为什么不在 initWithCoder 中

objective-c - 如何在按下空格键时禁用 Web FrameView 页面向下滚动?

iphone - 正则表达式名称和姓氏