Objective-c块寿命ARC

时间:2014-06-07 04:53:40

标签: objective-c objective-c-blocks

我对ARC下一个街区的生命周期感到困惑。我已经写了一个单元测试来证明让我困惑的事情。

- (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");
}

我猜这种行为与块如何存储在堆栈/堆上有关。

更新!

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

- (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");
}

1 个答案:

答案 0 :(得分:4)

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

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