2015-10-16 52 views
0

我們有這個奇怪的問題。 當我們實例化一個對象,我們也實例屬於該對象的屬性:當一個對象被實例化時,在將NSKeyValueNotifyObserver消息發送到釋放對象時,如何發生BAD ACCESS

-(instancetype)init 
{ 
    self = [super init]; 
    if (self) { 
    [self setDocument]; 
    } 
    return self; 
} 

-(void)setDocument: 
{ 
    _flatGraphicsArrayController = [[NSArrayController alloc] initWithContent:doc.flattenedObjects]; 
} 

...偶爾EXC_BAD_ACCESS發生在_flatGraphicsArrayController

調用棧設置:
enter image description here

此崩潰已被確定是由於將NSKeyValueNotifyObserver消息發送到釋放對象,該對象似乎正在觀察對flatGraphicsArrayController

對我來說,這是非常令人困惑的,因爲擁有這個屬性的對象剛被實例化,那麼怎麼可能觀察到屬性的變化?

是否有人註冊觀察一個特定的內存地址(如果這是它是如何工作的),然後flatGraphicsArrayController以某種方式佔用了內存中的空間,而觀察者被釋放?

回答

2

某些對象(Object1)作爲觀察者添加到另一個對象(Object2)。在此之後的某個時間,Object1和Object2都被釋放,但是沒有任何Object1作爲Object2的觀察者移除。鍵值觀察者之間的關係保持在兩個對象之外(因爲當添加KVO時,由於二進制兼容性的原因,不能將新的實例變量添加到NSObject,因此它必須將其狀態存儲在副表中)。

KVO應該在釋放Object1時抱怨這一點。檢查控制檯日誌。

無論如何,在稍後的時間,您創建您的實例NSArrayController。它恰好佔用與Object2相同的地址。這意味着它匹配KVO關於Object1和Object2之間觀察關係的內部信息。所以,實際上,已停用的Object1現在正在觀察您的陣列控制器。當其屬性發生更改時,它會將KVO更改通知發送到Object1。當然,Object1不再存在。根據地址是否被重用以及該地址是新對象的基地址還是指向其中某處的地址,結果可能是崩潰或無聲。

要解決這個問題,您需要在釋放觀察或觀察對象之前始終刪除KVO觀察值。

+0

感謝您的回答;這就是問題所在。當一個不同類型的對象佔據舊Object2的內存空間時會發生什麼? –

+0

不客氣。我不確定你在問什麼。在這種情況下,「不同類型的對象佔用舊Object2的內存空間」的可能性很大。這纔是重點。 –

+0

因此,KVO系統不關心被觀察的對象 - 如果它被釋放並被不同類型的對象替換,並且新對象改變,它仍然發送通知?例如,某事正在觀察一個Person對象。人獲得釋放。 Dog對象替換它在內存中的位置。 Dog對象發生變化,原始觀察者是否會收到通知?或者,如果Person對象被另一個人取代,原始觀察者只會得到通知? –

相關問題