gpt4 book ai didi

ios - 从单元格到托管对象的 keyValue 观察者

转载 作者:行者123 更新时间:2023-11-29 01:17:51 25 4
gpt4 key购买 nike

我正在查看此处的表格 View 单元格,并找到以下代码:

- (void)awakeFromNib {
[super awakeFromNib];
[self addObserver:self forKeyPath:@"model.isDownloading" options:NSKeyValueObservingOptionNew context:NULL];
[self addObserver:self forKeyPath:@"model.isCached" options:NSKeyValueObservingOptionNew context:NULL];
[self addObserver:self forKeyPath:@"model.isOutDated" options:NSKeyValueObservingOptionNew context:NULL];
[self addObserver:self forKeyPath:@"model.cacheUpdateDate" options:NSKeyValueObservingOptionNew context:NULL];
[self addObserver:self forKeyPath:@"model" options:NSKeyValueObservingOptionNew context:NULL];
}

观察者在dealloc方法中被删除。 model 是一个weak 属性,接收托管对象(核心数据)。

我收到虚假崩溃,告诉我托管对象已删除,但仍有观察者注册。

为什么发生错误对我来说非常清楚:该对象在后台某处被删除,但仍然链接到表格 View 的单元格中。由于在应用程序的生命周期内基本上不会调用单元上的dealloc,因此观察者永远不会真正被删除。由于对 core-data 对象的引用是,因此它将在后台默默地释放 - 至少会尝试这样做。这失败了,因为模型仍然被观察到。

我有一些问题:

  • 如果观察到像“model.isDownloading”这样的路径,则观察者注册在 model 对象中,而不是在 self 的 setter 中,对吗?
  • 如果重新分配 model,objC 是否足够智能来处理观察者更改(self.model = newThing 需要,调用 removeObserver分配 newThing 之前的 model,之后需要在 newThing 上注册观察者)。
  • 由于崩溃发生在托管对象的dealloc上,我认为一个简单的解决方案是使model强而不是weak,当然还要确保,在 prepareForReuse: 中将其正确设置为 nil。这是否有我没有意识到的副作用?

错误信息是:

类 xxx 被释放,而键值观察者仍然在其中注册

最佳答案

如果观察到像“model.isDownloading”这样的路径,那么观察者是在model对象中注册的,而不是在self中的setter中,是对吗?

这是一个很好的问题。据我之前所知,当一个对象注册到 KVO 时,运行时至少会跟踪两件事
1) 正在观察和
的对象2) 它正在观察的属性的键路径。

我们知道运行时会覆盖属性的 setter 以通知观察到更​​改的对象。

但很明显,运行时还必须跟踪正在观察的对象,否则在仍有观察者注册的情况下,它如何知道它是否正在被释放?

运行时似乎解析了点的keyPath,并遵循来自接收器的引用链(在您的示例中为self),以跟踪观察到的对象(self.model)

如果 model 被重新分配(self.model = newThing 要求,removeObserver,objC 是否足够聪明来处理观察者变化在分配 newThing 之前在 model 上调用,之后需要在 newThing 上注册观察者)。

不,它不够聪明。例如,运行时将您的 self.model 对象(假设它的类型为 Model)子类化以覆盖 isDownloading 的 setter .现在您的 self.model 对象是 NSKVONotifying_Model 类型。如果您要将 self.model 指针换成指向类型为 Model 的新对象,它就不会属于运行时创建的同一个 KVO 类。因此,该属性的 setter 不会添加用于通知观察者的指令。所以是的,你必须删除第一个对象上的观察者并将其添加到第二个对象,即使你使用的是相同的指针变量。

由于崩溃发生在托管对象的 dealloc 上,我认为一个简单的解决方案是,使 model 强而不是 weak,当然确保在 prepareForReuse: 中将其正确设置为 nil。这是否有我没有意识到的副作用?

这是正确的,但如您所知,如果您引用的 model 对象被换出,您将不得不重新添加观察者。

另一种选择(如果您可以更改 Model 类),是在 Model 类中添加一个引用回到您的 self这个上下文。然后在 Model 类的 init/dealloc 中,您可以将其自身添加为新引用的观察者。

最后要注意的是,如果您发现自己发送了一个 addObserver 消息,而接收者 观察者对象是相同的——您也可以覆盖 setter自己。

在您的示例中,您可以重写 -setModel 以执行您在观察通知处理程序 (-observeValueForKey:::) 中要做的任何事情

关于ios - 从单元格到托管对象的 keyValue 观察者,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34950610/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com