实例已被解除分配,而关键价值观察员仍在其中注册

时间:2014-07-31 10:46:43

标签: ios objective-c nsnotificationcenter

我有一个UITableView。

在这里,我得到了不同的细胞。每个细胞都有一个模型。使用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>
)

在单元格中,我在设置/更改模型属性时执行此操作:

[_model addObserver:self
         forKeyPath:@"name"
            options:0
            context:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(modelIsInvalid:)
                                             name:@"modelIsInvalid"
                                           object:_model];

然后在单元格的dealloc中:

- (void)dealloc
{
    NSLog(@"DEALLOC CELL");
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [_model removeObserver:self forKeyPath:@"name"];
}

在模型中,我还检查它何时被解除分配:

- (void)dealloc
{
    NSLog(@"DEALLOC MODEL");
}

在所有模型之前,所有单元格都被释放,但我仍然遇到此错误。另外我不确定如何设置错误中提到的断点。

5 个答案:

答案 0 :(得分:7)

它不会起作用,因为细胞正在重复使用。因此,当单元格离开屏幕时,它没有被释放,它会重新使用池。

您不应该在单元格中注册通知和KVO。您应该在表视图控制器中执行此操作,当模型更改时,您应该更新模型并重新加载可见单元格。

答案 1 :(得分:6)

我找到了答案。我无法删除该帖子,有人回答:)也许这对某人有用。

问题在于UITableView会将之前使用的相同单元格出列,对于更长的行(在滚动得足够远时变得可见)。

在我现在的制定者中:

// 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];

答案 2 :(得分:4)

根据接受的答案(这是正确的),你可以通过删除&#34; prepareForReuse &#34;上的观察者来解决它。细胞的方法。

在重复使用滚动等单元格之前,将调用该方法。因此,您不会有任何问题。

- (void)prepareForReuse{
    [_model removeObserver:self forKeyPath:@"name"];
}

答案 3 :(得分:0)

您的视图控制器可能没有调用dealloc方法,因为它的引用可能由某人持有,并且您的dealloc方法未被调用。您可以使用viewDidUnload:viewWillDisappear:方法删除观察者,也可以将控制器追踪到乐器中以进行任何保留

答案 4 :(得分:0)

为单元格和可重用视图执行此操作的最佳位置是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") } }