在下面的代码中,ARC'd并在Mac OS X 10.8.4上运行64位,为什么MyObj的实例在程序终止之前没有被释放?
#import <Foundation/Foundation.h>
@interface MyObj : NSObject
@end
@implementation MyObj
- (void)dealloc
{
NSLog(@"MyObj dealloc'd %p", self);
}
@end
int main(int argc, const char * argv[])
{
MyObj* obj1 = [[MyObj alloc] init];
__weak MyObj* weakObj1 = obj1;
NSLog(@"Use it: %p\n", weakObj1);
// Why isn't MyObj deallocated here?
return 0;
}
答案 0 :(得分:3)
__ weak依赖于Objective-C运行时函数objc_loadWeak。来自Clang 3.4文档中的 Objective-C自动引用计数:
id objc_loadWeak(id * object);
前提条件:对象是一个有效的指针,它包含一个null 指针或已注册为 __弱对象。
如果对象被注册为 __弱对象,并且存储了最后一个值 进入对象尚未解除分配或开始解除分配, 保留和自动释放,重视并返回它。否则返回 空值。相当于以下代码:
id objc_loadWeak(id *object) { return objc_autorelease(objc_loadWeakRetained(object)); }
对于对象上 objc_storeWeak 的调用,必须是原子的。
<强>原理强>
加载弱引用本身就容易发生竞争 没有保留的条件。
由于objc_loadWeak需要自动释放池,因此在使用__weak时必须存在自动释放池。该池可以由NSAutoreleasePool或@autoreleasepool创建。如果自动释放池不存在,那么在objc_loadWeak保留它之后,任何东西都不会释放你的对象,因此你的对象永远不会被释放。
以下是上述代码的修复:
#import <Foundation/Foundation.h>
@interface MyObj : NSObject
@end
@implementation MyObj
- (void)dealloc
{
NSLog(@"MyObj dealloc'd %p", self);
}
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
MyObj* obj1 = [[MyObj alloc] init];
__weak MyObj* weakObj1 = obj1;
NSLog(@"Use it: %p\n", weakObj1);
// Now MyObj is deallocated
}
return 0;
}
答案 1 :(得分:1)
在主要结束之前,不会释放weakObj1。当您使用ARC时,您应该这样做,变量和对象将不会被释放,直到声明它们的块结束。发生这种情况时,所有未被任何对象强引用的对象都将被释放。
请记住,要解除分配对象,必须向其发送一条释放消息。如果你使用手动保留释放MRR,你必须自己做,如果你使用自动引用计数,ARC,系统会为你做。