2013-06-21 33 views
0

在以下代码中,ARC'd在Mac OS X 10.8.4上运行64位,为什么MyObj实例在程序终止之前未被释放?为什么在自动释放池之外使用__weak引用它们时不会释放对象?

#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; 
} 

回答

3

__weak依赖于Objective-C运行时函数objc_loadWeak。从Objective-C的自动引用的文档中计数为锵3.4:

ID objc_loadWeak(ID *对象);

前提对象是有效的指针其或者包含一个空指针 或已被注册为__weak对象。

如果对象注册为__weak对象,最后的值保存到 对象尚未释放或开始释放, 保留并自动释放该值并将其返回。否则返回 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

weakObj1不会被释放,直到主结束。当你使用ARC时,你应该这样做,变量和对象将不会被释放,直到它们被声明的块被结束。发生这种情况时,所有不被任何对象强引用的对象都将被释放。

请记住,释放消息必须发送给它释放一个对象。如果您正在使用手动扣留释放MRR,您必须自行完成,如果您使用自动引用计数,ARC,则系统会为您执行此操作。

+0

*“对象或变量将被释放,一旦它声明的块结束”* - 这是错误的。一个*强参考*将在该块的结尾处发布。如果最后一个强引用被释放,该对象将被释放。但'__weak MyObj * weakObj1 = obj1;'创建一个*弱引用*,不会增加保留计数。 –

+0

weakObj1对obj1的引用较弱,表示weakObj1不会增加obj1的保留计数;但这并不意味着弱Obj1本身没有保留计数。这个保留计数将在创建对象时保留一次,并且直到它减少到0时才会被释放。在ARC中,它仍然取决于autoreleasepool被释放。 –

+0

你说得对,但答案中的那句话误导了你,也许你可以改变它。 –