《Cocoa编程开发者手册》:
这个方法从一个保护条件开始,如果收到的通知是错误的对象类型,则立刻中断。这不是必需的,但是所有KVO通知都会被派发到同一个方法中,所以应该多做一些事情保证安全。如果不是在调试,你可能会想不用这段代码,或者在return语句之前设置一个断点,以便在调用错误的时候修正它。
这个方法的主体就是一个大的switch语句,以NSKeyValueChangeKindKev为键的整数值作为条件,这个值保存在change字典中。这样可以知道是否发生了这种变化。我们支持三种情况:改变键,增加一个子项,移除子项。还有一种情况是替换集合中的一个对象,但我们目前的模型不支持这种做法,所以也就不需要处理这种情况了。
第一种情况在73.86行(代码清单9.11)。目前只由项目标题变化引发。你可能会觉得这部分代码比我们需要的复杂,下面这段更简单的代码可以替换77—83行。
这样确实简单一些,但有一个严重问题:这段代码根本不工作。如果实现了一个这样的方法,那么会在运行记录中看到这样的提示:2009.01.2012:44:44.682 0utliner[27412:813]Error setting value for key path title of object(from bound object(null)):[setValue:forUndefinedKey:]:this class is not key valuecoding—compliant for the key title.
这个错误是由撤销管理器实现的缺陷造成的。prepareWithInvocationTarget:本应返回一个NSProxy的子类。NSProxy是root对象的替代品,它遵循NSObject协议,但是在方法上只实现了一个小的子集。它用于代理对象,因为几乎所有发送给它的消息都会触发—forwardlnvocation:调用,允许转发。不幸的是,在这里NSUndoManager返回的是NSObject子类(其实就是它本身)。
这问题很明显,当发送给NSUndoManager一个对应的消息时,其中实现的任何方法都会简单地被调用。转发机制不起作用了。
创建撤销时,这是相当严重的问题。你无法通过一prepareWithInvationTarget:机制调用NSObject和NSUndoManager实现的任何方法。虽然NSObject实现了基本的KVC机制,也无法在这里使用。
幸好有一个替代方案。NSObject中有一些后备代码,可以给所有的转发机制构建一个调用,并传给一forwardlnvocation:。我们不能用这些代码来自动构建调用,但仍然可以调用一forwardlnvocation:。每当发送一个由NSObject实现的消息来处理撤销动作时,都会因此而造成一点点麻烦。
……
展开