ios 实例已被释放,而键值观察者仍在向其注册
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25056942/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Instance was deallocated while key value observers were still registered with it
提问by Johannes
I've got a UITableView.
我有一个 UITableView。
Here I got different cell's. Each cell has a model. With KVO and NotificationCenter the cell listen to the model for changes. When I leave the ViewController I get this error:
在这里,我得到了不同的细胞。每个单元格都有一个模型。使用 KVO 和 NotificationCenter,单元会监听模型的变化。当我离开 ViewController 时,出现此错误:
An instance 0x109564200 of class Model 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 0x109429cc0> (
<NSKeyValueObservance 0x109429c50: Observer: 0x10942d1c0, Key path: name, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x10968fa00>
)
In the cell I do this when the model property is set/changed:
在单元格中,我在设置/更改模型属性时执行此操作:
[_model addObserver:self
forKeyPath:@"name"
options:0
context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(modelIsInvalid:)
name:@"modelIsInvalid"
object:_model];
Then in the cell's dealloc:
然后在单元格的 dealloc 中:
- (void)dealloc
{
NSLog(@"DEALLOC CELL");
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_model removeObserver:self forKeyPath:@"name"];
}
In the model I also check when it get's deallocated:
在模型中,我还检查它何时被释放:
- (void)dealloc
{
NSLog(@"DEALLOC MODEL");
}
All cell's are deallocated before all the models, but still I get this error. Also I'm not sure how to set the breakpoint mentioned in the error.
在所有模型之前释放所有单元格,但我仍然收到此错误。另外我不确定如何设置错误中提到的断点。
采纳答案by Greg
It won't work because the cells are being reused. So when the cell goes off the screen it's not deallocated, it goes to reuse pool.
它不会工作,因为细胞正在被重用。因此,当单元格离开屏幕时,它不会被释放,而是进入重用池。
You shouldn't register notifications and KVO in cell. You should do it in table view controller instead and when the model changes you should update model and reload visible cells.
您不应该在单元格中注册通知和 KVO。您应该在表视图控制器中执行此操作,当模型更改时,您应该更新模型并重新加载可见单元格。
回答by Johannes
I found the answer. I can't delete the thread, someone has answered :) Maybe it will be useful for someone.
我找到了答案。我无法删除该线程,有人已回答:) 也许它对某人有用。
The problem is that the UITableView will dequeue the same cell used before, for a row longer down (that becomes visible when scrolling far enough).
问题是 UITableView 会将之前使用的相同单元格出列,向下行更长的时间(滚动足够远时变得可见)。
In the setter I now have:
在二传手中,我现在有:
// Before we set new model
if (_model) {
[_model removeObserver:self forKeyPath:@"name"];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"modelIsInvalid" object:_model];
}
_model = model;
[_model addObserver:self
forKeyPath:@"name"
options:0
context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(modelIsInvalid:)
name:@"modelIsInvalid"
object:_model];
回答by PakitoV
Based on the accepted answer (which is correct) you can solve it by removing the observer on the "prepareForReuse" method of the cell.
根据接受的答案(这是正确的),您可以通过移除单元格的“ prepareForReuse”方法上的观察者来解决它。
That method will be called before reusing the cell on scrolling etc.. thus you wont have any problem.
该方法将在滚动等重用单元格之前调用。因此你不会有任何问题。
- (void)prepareForReuse{
[_model removeObserver:self forKeyPath:@"name"];
}
回答by Basheer_CAD
The best place to do this for Cells and Reusable views is in willMove(toSuperiew)
对单元格和可重用视图执行此操作的最佳位置是 willMove(toSuperiew)
override func willMove(toSuperview newSuperview: UIView?) {
if newSuperview == nil { // check for nil means this will be removed from superview
self.collectionView?.removeObserver(self, forKeyPath: "contentSize")
}
}
override func willMove(toSuperview newSuperview: UIView?) {
if newSuperview == nil { // check for nil means this will be removed from superview
self.collectionView?.removeObserver(self, forKeyPath: "contentSize")
}
}
回答by Retro
There may be a possibility that your view Controller is not calling dealloc method because it's reference might be hold by someone and your dealloc method is not getting called. You can remove observer at your viewDidUnload:
or viewWillDisappear:
method or you can trace your controller into instrument for any retain
您的视图控制器可能没有调用 dealloc 方法,因为它的引用可能被某人持有,而您的 dealloc 方法没有被调用。您可以在您的viewDidUnload:
或viewWillDisappear:
方法中删除观察者,或者您可以将您的控制器跟踪到仪器中以进行任何保留