Objective-c块寿命弧

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

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

块是在堆栈上创建的,并且在范围退出时才被破坏,就像是用析构函数分配的C++堆栈对象。这些块不受引用计数的限制,将忽略

保留
/
释放
消息。只有在被复制后(通过
Block\u copy()
函数或
copy
消息),它们才成为可以保留和释放的正常堆分配对象


在您的示例中,如果您将前面的所有代码都用额外的花括号括起来,那么assert将开始工作,这样assert将在块变量的作用域结束后执行。

非常棒,谢谢。我尝试了
copy
,但我很确定我所做的只是将块添加到堆栈之外的堆中。块的行为在很多方面都像对象引用,类似这样的东西真的会让你大吃一惊。