我对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");
}
答案 0 :(得分:4)
块在堆栈上创建,只有在作用域退出时才会被销毁,就像使用析构函数的C ++堆栈分配对象一样。这些块免于引用计数,并且忽略 retain
/ release
消息。只有在被复制(通过Block_copy()
函数或copy
消息)后,它们才会成为正常的堆分配对象,可以保留和释放。
在您的示例中,如果您将所有代码包装在额外的大括号{
}
中,则断言将开始工作,以便断言变量的范围结束后执行断言。