【问题标题】:Objective-c block lifetime ARCObjective-c 块生命周期 ARC
【发布时间】:2014-06-07 04:53:40
【问题描述】:

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

【问题讨论】:

    标签: objective-c objective-c-blocks


    【解决方案1】:

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

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

    【讨论】:

    • 太棒了,谢谢。我尝试了copy,但我很确定我所做的只是将块添加到堆栈和堆栈。块在很多方面都表现得像对象引用,这样的东西真的会让你失望。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-07
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    相关资源
    最近更新 更多