2011-03-04 53 views
0

有許多Foundation類允許您提供一個指向void的指針,該指針稍後作爲參數傳遞給回調函數。例如,addKeyserver:forKeyPath:options:context:of NSKeyValueObserving。與可可中的void *上下文相關的內存管理

由於指向void的指針可能無法擴展NSObject,因此接受此類參數的函數不能期望保留它。因此,您的代碼必須看起來類似於以下內容:

- (void)sharedInit 
{ 
    MyObject *myObject = [[MyObject alloc] init]; 
    [x addObserver:y forKeyPath:@"z" options:0 context:myObject]; 
    // cannot (auto)release myObject here 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    MyObject *myObject = (MyObject *)context; 
    [myObject release]; // myObject is released here 
}

這是有道理的,但它似乎違背了可可/ Objective-C的對象所有權的每一個原則。另外,如果你忘記在這種情況下手動管理內存,它經常(儘管不總是)導致EXC_BAD_ACCESS崩潰。此外,Xcode分析器抱怨。

我問這個問題的原因是因爲我正在編寫一個網絡連接庫,在其公共API中使用相同類型的上下文指針。然而,在我自己的代碼中需要跟蹤一些內存管理錯誤,這些錯誤與所需的手動內存管理有關,我相信必須有更好的方法。一種解決方案是將API的上下文參數類型更改爲(id <NSObject>),而不是(void *)。

爲什麼Foundation類經常使用(void *)而不是(id <NSObject>)?

回答

2

MHC對於推理是正確的。沒有要求該對象是NSObject。但正如你注意到的那樣,你在這裏無論如何都在錯誤地進行內存管理。

而不是泄漏對象,然後嘗試清理它,在這種情況下管理對象的常見模式是將其存儲爲註冊類的ivar。另一種常見模式是通過self作爲上下文,確保在-dealloc期間取消註冊回調。

1

因爲它並不總是id。數據可以是C結構,也可以是Core Foundation對象,甚至是標量。