Objective-c ARC Block Life

I got confused in the life of a block under ARC. I wrote a unit test to demonstrate what bothers me.

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

I assume this behavior has something to do with how the blocks are stored on the stack / heap.

Update!

Setting a block to nil does not release the block as I expected, because it is on the stack and will not be released until it goes out of scope. Forcing a block to exit the scope corrects my test. Updated code below.

 - (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"); } 
+4
objective-c objective-c-blocks
source share
1 answer

Blocks are created on the stack and become destructible only when a region is deleted that is largely similar to objects with a selected C ++ glass with destructors. These blocks are freed from reference counting and ignore retain / release messages. Only after copying (via the Block_copy() function or copy message) do they become normal objects selected by a bunch that can be saved and freed.

In your example, the statement will start to work if you complete all the code before it in extra curly brackets { } , so that assert will be executed after the block variable area has completed.

+4
source share

All Articles