Objective-c块寿命弧
我对ARC下块的寿命感到困惑。我已经编写了一个单元测试来证明什么让我困惑Objective-c块寿命弧,objective-c,objective-c-blocks,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
- (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");
}
块是在堆栈上创建的,并且在范围退出时才被破坏,就像是用析构函数分配的C++堆栈对象。这些块不受引用计数的限制,将忽略
保留
/释放
消息。只有在被复制后(通过Block\u copy()
函数或copy
消息),它们才成为可以保留和释放的正常堆分配对象
在您的示例中,如果您将前面的所有代码都用额外的花括号括起来,那么assert将开始工作,这样assert将在块变量的作用域结束后执行。非常棒,谢谢。我尝试了
copy
,但我很确定我所做的只是将块添加到堆栈之外的堆中。块的行为在很多方面都像对象引用,类似这样的东西真的会让你大吃一惊。