2013-06-21 36 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

你說得對,但答案中的那句話誤導了你,也許你可以改變它。 –