Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c NSProxy与关键值观察_Objective C_Cocoa_Key Value Observing_Nsproxy - Fatal编程技术网

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,然后更改为另一个非nil值
  • 目标为
    nil
    (不在init上),稍后变为非
    nil
  • …在案例1中,我们马上就遇到了问题。如果KVO观察者只观察到
    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
    的过程中永远不会知道更新其内部状态)
  • 强制任何目标对象具有一种机制,使其临时撒谎并从valueForKey返回
    nil
    :对于所有键来说,这似乎是一个相当繁重的要求,因为所述的愿望是“透明代理”
  • 在具有
    nil
    目标的代理上调用setValue:forKey:意味着什么?我们是否保持这些价值观?等待真正的目标?我们扔吗?巨大的悬而未决的问题
  • 对这种方法的一种可能的修改是在实际目标为
    nil
    时使用代理目标,可能是空的
    NSMutableDictionary
    ,并将KVC/KVO调用转发给代理。这将解决无法在
    nil
    上有意义地调用
    willChangeValueForKey:
    的问题。综上所述,假设您保留了您的观察列表,我并不乐观KVO是否会容忍在案例1中设定目标所涉及的以下顺序:

  • 外部观察者调用
    -[proxy addObserver:…]
    ,代理将转发到字典代理
  • 代理调用
    -[subrogate willChangeValueForKey:
    ],因为正在设置目标
  • 代理调用代理上的[Subrogate removeObserver:…]
  • 代理在新目标上调用
    -[newTarget addObserver:…]
  • 代理调用
    -[newTarget didChangeValueForKey:
    ]以平衡调用#2
  • 我不清楚这是否也会导致同样的错误。这整个方法真的是一团糟,不是吗

    我确实有一些备选想法,但#1相当琐碎,而#2和#3不够简单,也不够自信,因此我想浪费时间编写代码。但对后人来说,,
        id old = object_getIvar(realObject, backingVar);
        object_setIvar(realObject, backingVar, nil);
        [realObject willChangeValueForKey:propertyName];
        object_setIvar(realObject, backingVar, old);
        [realObject didChangeValueForKey:propertyName];