我正在查看表格视图单元格,我找到了这段代码:
- (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
属性,接收托管对象(核心数据)。
我收到虚假的崩溃,告诉我,托管对象被删除了,但仍然注册了观察者。
为什么错误发生对我来说非常清楚:对象在后台的某处被删除,但仍然链接到tableview的单元格中。由于单元格上的dealloc
基本上从未在应用程序的生命周期内被调用,因此观察者永远不会被删除。由于对核心数据对象的引用是weak
,它将在后台静默释放 - 至少尝试一下。这失败了,因为仍然可以观察到模型。
我有一些问题:
model
对象中注册,而不是self
中的设置者,是正确的吗?model
self.model = newThing
,removeObserver
需要,model
在分配newThing
之前调用newThing
,objC是否足够聪明以处理观察者更改,并且观察员需要在model
之后注册。weak
强而不是nil
,当然要确保它已正确设置为prepareForReuse:
中的class xxx was deallocated while key value observers were still registered with it
。这有副作用吗,我还没有意识到?错误消息是:
/// <summary>
/// Computes the PBKDF2-SHA1 hash of a password.
/// </summary>
/// <param name="password">The password to hash.</param>
/// <param name="salt">The salt.</param>
/// <param name="iterations">The PBKDF2 iteration count.</param>
/// <param name="outputBytes">The length of the hash to generate, in bytes.</param>
/// <returns>A hash of the password.</returns>
private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
{
var pdb = new Pkcs5S2ParametersGenerator();
pdb.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(password.ToCharArray()), salt,
iterations);
var key = (KeyParameter)pdb.GenerateDerivedMacParameters(outputBytes * 8);
return key.GetKey();
}
答案 0 :(得分:1)
如果观察到像“model.isDownloading”这样的路径,那么观察者在model
对象中注册,而不是self
中的setter,这是正确的吗?
这是一个非常好的问题。据我所知,当一个对象用KVO注册时,运行时至少会记录两件事情
1) 观察的对象和
2)它正在观察的属性的关键路径。
我们知道运行时会覆盖属性的setter,以通知观察到更改的对象。
但显然运行时还必须跟踪被>>观察到的对象,否则如果仍有观察者注册的话,它是否会知道它是否被释放?
运行时似乎解析了keyPath
的点,并跟随接收器的参考链(在您的示例中为self
),以跟踪观察到的对象(self.model
)
如果model
需要重新分配self.model = newThing
,那么objC足够聪明,可以处理观察员更改removeObserver
在model
上调用newThing
,然后再分配newThing
然后需要在self.model
之后注册观察者。
不,它不够聪明。例如,运行时将Model
对象(我们说它的类型为isDownloading
)子类化为覆盖self.model
的setter。现在,您的NSKVONotifying_Model
对象的类型为self.model
。如果要将Model
指针交换为指向model
类型的新对象,则它将与运行时创建的KVO类不同。因此,属性的setter不会添加指令以通知观察者。
所以是的,您必须删除第一个对象上的观察者并将其添加到第二个对象,即使您使用相同的指针变量。
由于崩溃发生在托管对象的dealloc上,我认为一个简单的解决方案是使weak
强而不是nil
,当然要确保它是在prepareForReuse:
中正确设置为model
。这是否有副作用,我还没有意识到?
这是正确的,但正如您所知,如果您的引用的Model
对象被换出,您将不得不重新添加观察者。
另一种替代方法(如果您可以更改Model
类)是在此上下文中将self
类中的引用添加回init
。然后,在dealloc
课程的Model
/ addObserver
中,您可以将自己添加为新参考的观察者。
最后要注意的是,如果您发现-setModel
消息,其中接收者和的观察者对象是相同的 - 您也可以自己覆盖设置者。< / p>
在您的示例中,您可以覆盖-observeValueForKey:::
来执行您在观察通知处理程序中执行的任何操作(class Foo:
pass
foo = Foo()
setattr(foo, 'bar', 42)
print(foo.bar) # 42
)