2012-05-29 35 views
35

我有一個weak屬性爲其超級視圖(視圖B)的​​視圖(我們稱之爲視圖A)。查看KVO的超級視圖,查看B.由於視圖A對視圖B的引用是一個弱屬性(以防止保留週期),我怎樣才能移除觀察者(A觀察B)?查看A對視圖B的引用在我有機會刪除它之前沒有被刪除。如何從弱財產中清除KVO?

甲會超越乙由於視圖控制器具有強引用A.這裏的泄漏日誌消息:

An instance 0x9ac5200 of class UITableView was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here's the current observation info: 
<NSKeyValueObservationInfo 0x8660360> (
<NSKeyValueObservance 0x8660320: Observer: 0x8660020, Key path: contentOffset, Options: <New: YES, Old: NO, Prior: NO> Context: 0x8660020, Property: 0x864ac80> 
) 

B是一個UITableView。在NSKVODeallocateBreak處設置斷點會產生無用的結果。

在A的removeFromSuperview中,我嘗試刪除觀察者,但A對B的引用已經是nil

切換到unsafe_unretained並在視圖控制器的dealloc中手動執行更多操作或調用[A removeFromSuperview]可解決此問題。我想知道如何使用weak屬性來解決這個問題。

下面是相關代碼:https://gist.github.com/2822776

+0

我的不好... +1無論如何。 – CodaFi

回答

1

你可以定義一個明確的弱屬性引用上海華再觀察self與像@"propertyReferringSuperview.propertyOfSuperview"的關鍵路徑?當您收到KVO通知時,您會檢查是否self.propertyReferringSuperview == nil並停止觀察@"propertyReferringSuperview.propertyOfSuperview"

+1

我試過這種方法。當超視圖的弱引用被排除時,KVO不會觸發。 –

+0

真是太遺憾了......也許試着把清理插入到setPropertyReferringSuperview中:我希望在弱參考變爲'無'時調用它。實際上,你可以在這個制定者中開始並停止觀察權利。 – Stream

+0

這是一個很好的答案。當superview被排除時,你不需要將自己作爲觀察者移除。你可以保持一個觀察者,直到你和你交易。所以,只需註冊以在init中偵聽(即使您的屬性爲零,這也可以),然後在dealloc(或deinit)中取消註冊。 – plivesey

2

我發現這種情況下特別需要的任何類型的代碼實際上是不必要的,因爲可以自動刪除。

隨着ARC的推出,蘋果應該提供自動刪除觀察者來修復這種情況,但不幸的是他們沒有。但是,我做了我自己的類別,增加了這個功能不足:https://github.com/krzysztofzablocki/SFObservers 我解釋我是如何做到管理該在我的博客:http://www.merowing.info/2012/03/automatic-removal-of-nsnotificationcenter-or-kvo-observers/

如果你看一下我的解決方案,你會發現,它可以確保原代碼的調用,即使其中一種方法調用其他的人,所以,即使蘋果改變其內部行爲的類別將仍然工作得很好:)不是添加弱財產

+0

您的SFOvservers看起來很酷。我希望能夠使用一個不那麼聰明的解決方案。 NSObject上的Swizzling東西有點嚇人。誰知道他們會在iOS 6中改變什麼。 –

+0

這就是爲什麼我的解決方案不會假定原始方法的任何順序,而是調用原始代碼:-)所以,如果他們改變任何東西,這是未來的證明。 –

0

,你可以只使用superview財產實施willMoveToSuperview:添加/刪除KVO觀察。

- (void)willMoveToSuperview:(UIView *)newSuperview { 
    [self.superview removeObserver:self forKeyPath:@"contentOffset" context:context]; 
    [newSuperview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:context]; 
    [super willMoveToSuperview:newSuperview]; // optional as default implementation does nothing 
} 
+0

當調用'willMoveToSuperview:'時,引用視圖B的弱屬性(或Gist中的'scrollView')已經是'nil'。 –

+0

是的,但你告訴那個視圖B是A的超級視圖。所以你不需要'scrollView'屬性。只需使用'superview'。 –