我遇到了一个问题,即即使所有对象和块的引用都设置为nil
之后,块内捕获的对象似乎也不会被释放。
为了说明这个问题,我把这个非常简单的单元测试放在一起,应该通过但不会:
/* Headers */
@interface BlockTestTests : XCTestCase
@end
// A simple class that calls a callback when it's deallocated
@interface Dummy : NSObject
@property (nonatomic, copy) void(^deallocCallback)();
@end
/* Implementation */
@implementation BlockTestTests
- (void)testExample {
XCTestExpectation *exp = [self expectationWithDescription:@"strong reference should be deallocated when its capturing block is released"];
Dummy *dummy = [Dummy new];
dummy.deallocCallback = ^{
[exp fulfill];
};
void(^capturingBlock)() = ^{
// Captures a strong reference to the dummy
id capturedStrongReference = dummy;
};
capturingBlock = nil;
dummy = nil;
// At this point we would expect that all references to the
// object have been cleared and it should get deallocated.
// Just to be safe, we even wait 2 seconds, but it never happens...
[self waitForExpectationsWithTimeout:2.0 handler:nil];
}
@end
@implementation Dummy
- (void)dealloc {
_deallocCallback();
}
@end
你能告诉我为什么这个测试失败了吗?
答案 0 :(得分:2)
你的capturingBlock
正在创建一个自动释放的对象(可能是通过捕获,但可能是块本身)。如果你在它周围放置一个@autoreleasepool
,它会做你想做的事情:
@autoreleasepool {
void(^capturingBlock)() = ^{
// Captures a strong reference to the dummy
id capturedStrongReference = dummy;
};
capturingBlock = nil;
dummy = nil;
}
更一致的方法是在整个测试中放置@autoreleasepool
(在创建exp
之后和waitForExpectations...
之前)。对于要验证对象是否在池耗尽时释放的任何测试,您可以执行此操作。像这样:
- (void)testExample {
XCTestExpectation *exp = [self expectationWithDescription:@"strong reference should be deallocated when its capturing block is released"];
@autoreleasepool {
Dummy *dummy = [Dummy new];
dummy.deallocCallback = ^{
[exp fulfill];
};
void(^capturingBlock)() = ^{
// Captures a strong reference to the dummy
id capturedStrongReference = dummy;
};
capturingBlock = nil;
dummy = nil;
}
[self waitForExpectationsWithTimeout:2.0 handler:nil];
}