Objective c NSProxy与关键值观察
Objective c NSProxy与关键值观察,objective-c,cocoa,key-value-observing,nsproxy,Objective C,Cocoa,Key Value Observing,Nsproxy,NSProxy似乎可以很好地作为尚未存在的对象的替代对象。比如说 - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { return [self.target methodSignatureForSelector:sel]; } - (void)forwardInvocation:(NSInvocation *)invocation { [invocation invokeWithTarget:self.tar
NSProxy
似乎可以很好地作为尚未存在的对象的替代对象。比如说
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
上述代码将透明地将任何方法调用传递给代理所表示的目标。但是,它似乎无法处理目标上的KVO观察和通知。我试图使用一个NSProxy
子类来表示要传递给NSTableView
的对象,但是我得到了以下错误
Cannot update for observer <NSAutounbinderObservance 0x105889dd0> for
the key path "objectValue.status" from <NSTableCellView 0x105886a80>,
most likely because the value for the key "objectValue" has changed
without an appropriate KVO notification being sent. Check the
KVO-compliance of the NSTableCellView class.
无法为的观察者更新
中的键路径“objectValue.status”,
很可能是因为键“objectValue”的值已更改
未发送适当的KVO通知。检查
NSTableCellView类的KVO遵从性。
有没有一种方法可以使透明的
NSProxy
与KVO兼容?问题的关键在于关键值观察的核心存在于NSObject
,而NSProxy
并不是继承自NSObject
。我有理由相信,任何方法都需要NSProxy
对象保留自己的观察列表(即外部人员希望观察到的内容)。仅此一点就可以为您的NSProxy实现增加相当大的权重
观察目标
看起来您已经尝试让代理的观察者实际观察真实对象了——换句话说,如果目标始终被填充,并且您只是将所有调用转发给目标,那么您也将转发addObserver:…
和removeObserver:…
调用。问题是你一开始就说:
对于那些
还不存在
为了完整起见,我将描述这种方法的一些胆识以及它无法工作的原因(至少在一般情况下):
为了使其工作,您的NSProxy
子类必须收集在设置目标之前调用的注册方法的调用,然后在设置目标时将它们传递给目标。当你认为你还必须处理移除时,这很快就会变得毛茸茸的;您不希望添加一个随后被删除的观察(因为观察对象可能已被解除锁定)。您可能也不希望跟踪观察的方法保留任何观察者,以免造成意外的保留周期。我看到了需要处理的目标值中的以下可能转换
nil
,之后变为非nil
nil
(不在init上),稍后变为非nil
objectValue
(因为这始终是您的代理),但假设观察者观察到一条通过您的代理/真实对象的关键路径,比如objectValue.status
,那么我们在这里可能就没问题了。这意味着KVO机器将调用观察目标上的valueForKey:objectValue
,并取回您的代理,然后将调用您的代理上的valueForKey:status
,并取回nil
。当目标变为非nil时,KVO将认为该值已从其下更改(即不符合KVO),您将收到您引用的错误消息。如果您有办法临时强制目标返回status
的nil
,您可以打开该行为,调用-[target willChangeValueForKey:status]
,关闭该行为,然后调用-[target didChangeValueForKey:status]
。无论如何,我们可以在案例1中到此为止,因为它们有相同的陷阱:
willChangeValueForKey:
,则nil
将不会执行任何操作(即,KVO机器在转换到或从nil
的过程中永远不会知道更新其内部状态)nil
:对于所有键来说,这似乎是一个相当繁重的要求,因为所述的愿望是“透明代理”nil
目标的代理上调用setValue:forKey:意味着什么?我们是否保持这些价值观?等待真正的目标?我们扔吗?巨大的悬而未决的问题nil
时使用代理目标,可能是空的NSMutableDictionary
,并将KVC/KVO调用转发给代理。这将解决无法在nil
上有意义地调用willChangeValueForKey:
的问题。综上所述,假设您保留了您的观察列表,我并不乐观KVO是否会容忍在案例1中设定目标所涉及的以下顺序:
-[proxy addObserver:…]
,代理将转发到字典代理-[subrogate willChangeValueForKey:
],因为正在设置目标-[newTarget addObserver:…]
-[newTarget didChangeValueForKey:
]以平衡调用#2 id old = object_getIvar(realObject, backingVar);
object_setIvar(realObject, backingVar, nil);
[realObject willChangeValueForKey:propertyName];
object_setIvar(realObject, backingVar, old);
[realObject didChangeValueForKey:propertyName];