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
Cocoa绑定和KVO,在观察对象“解除分配”时注销观察者`_Cocoa_Cocoa Bindings_Key Value Observing_Dealloc - Fatal编程技术网

Cocoa绑定和KVO,在观察对象“解除分配”时注销观察者`

Cocoa绑定和KVO,在观察对象“解除分配”时注销观察者`,cocoa,cocoa-bindings,key-value-observing,dealloc,Cocoa,Cocoa Bindings,Key Value Observing,Dealloc,当观察对象被解除分配时,如何注销观察者?? 当观察到的对象被解除分配时,cocoa绑定如何处理这种情况 通过使用手动KVO,我必须在dealloc对象之前移除观察(removeObserver)。。。Cocoa绑定如何处理此问题(停止观察观察对象的解除锁定)?来自KVO指南(强调矿):观察的键值addObserver:forKeyPath:options:context:方法不维护对观察对象、观察对象或上下文的强引用您应确保维护对观察对象和观察对象的强引用,以及必要的上下文 Cocoa绑定在bi

当观察对象被解除分配时,如何注销观察者??

当观察到的对象被解除分配时,cocoa绑定如何处理这种情况

通过使用手动KVO,我必须在
dealloc
对象之前移除观察(removeObserver)。。。Cocoa绑定如何处理此问题(停止观察观察对象的解除锁定)?

来自KVO指南(强调矿):观察的键值
addObserver:forKeyPath:options:context:
方法不维护对观察对象、观察对象或上下文的强引用您应确保维护对观察对象和观察对象的强引用,以及必要的上下文

Cocoa绑定在
bind:
unbind:
期间管理强引用

要回答您的问题“当观察对象被解除分配时,我如何注销观察者?”:您不注销观察者,因为观察者应该维护对观察对象的强引用。因此,观察到的对象不会被解除分配。

从另一个角度来看,你是在观察属性,而不是观察对象本身。因此,您只关心属性设置为nil时的情况。因为您作为观察者维护一个强引用,所以在观察对象完成观察之前,不会解除对观察对象的分配


因此,如果观察到的对象作为您正在观察的另一个对象的属性被删除,这将导致您停止观察它(释放强引用),然后允许释放观察到的对象。您正在观察的属性可能是对象的集合,因此您将观察正在删除的对象,从而停止观察并允许对象解除锁定

2017年更新

正如@GregBrown在评论中指出的,2013年的原始答案在2017年不起作用。我假设最初的答案在2013年起作用了,因为我的做法是在没有测试的情况下回答,但我不再使用任何代码

那么,2017年你们如何解决这个问题?最简单的答案是swizzling,有些人会发现这是一个矛盾,但在使用块时不需要这样做。以下是概念的快速证明,并附带以下注意事项:

  • 这不是线程安全的。考虑如果两个或多个线程同时执行代码会发生什么。标准技术将解决这一问题

  • 效率不是一个考虑因素!例如,您可能希望每个类swizzle
    dealloc
    一次,并在每个实例关联的对象中保留一个observer/keypath列表

  • 此代码仅支持自动删除,不能手动选择删除观察者。你可能希望改变这一点

守则:

@implementation AutoRemovedKVO

typedef void (*DeallocImp)(id, SEL);

+ (void)forTarget:(NSObject *)target
      addObserver:(NSObject *)observer
       forKeyPath:(NSString *)keyPath
          options:(NSKeyValueObservingOptions)options
          context:(nullable void *)context
{
   // register the observer
   [target addObserver:observer forKeyPath:keyPath options:options context:context];

   // swizzle dealloc to remove it

   Class targetClass = target.class;
   SEL deallocSelector = NSSelectorFromString(@"dealloc");
   DeallocImp currentDealloc = (DeallocImp)method_getImplementation(  class_getInstanceMethod(targetClass, deallocSelector) );

   // don't capture target strongly in block or dealloc will never get called!
   __unsafe_unretained NSObject *targetPointer = target;

   void (^replacementBlock)(id self) = ^(__unsafe_unretained id self)
   {
      if (self == targetPointer)
         [targetPointer removeObserver:observer forKeyPath:keyPath];

      currentDealloc(self, deallocSelector);
   };

   class_replaceMethod(targetClass, deallocSelector, imp_implementationWithBlock(replacementBlock), "v@:");
}

@end
\uuuuu unsafe\u unretained
的两种用法都是为了解决ARC的后果。在特定的方法中,通常保留其
self
参数,
dealloc
方法不保留参数,并且块遵循相同的retain-as-needed模型。要将块用作
dealloc
的实现,需要覆盖此行为,这正是
\uuuuuunsafe\uunrepaired
的用途

要使用上述代码,只需替换:

[b addObserver:a forKeyPath:keyPath options:options context:NULL];
与:

考虑到上述警告,上述代码将在2017年完成工作(未来几年无担保!)

2013年原始答案

这里概述了如何处理这种情况以及类似情况

首先查找关联的对象。简而言之,您可以将关联对象附加到任何其他对象(使用
objc\u setAssociatedObject
),并指定只要所附加的对象在周围,就应保留关联对象(使用
objc\u ASSOCIATION\u RETAIN

使用关联对象,可以安排在解除分配观察对象时自动删除观察者。设X为观察者,Y为观察对象

创建一个“unregister”类,比如Z,它(通过init)接受一个X&Y,并在其
dealloc
方法中执行
removeObserver

要设置观测,请执行以下操作:

  • 创建Z的实例,传递自身和Y
  • 将自己注册为Y的观察者
  • 把Z和Y联系起来
  • 现在,当Y被解除分配时,Z将被解除分配,这将导致调用Z的
    dealloc
    ,并注销对X的观察

    如果需要在Y仍处于活动状态时删除对X的观察,可以通过删除关联对象来执行此操作,这样做将触发其
    dealloc

    当您想要在另一个对象被释放时触发某些东西时,可以使用此模式


    HTH

    我尝试过并希望成功的模式:X想要观察Y

    1) 例如,你可以申报一项财产

    @property (assign) id dealloced;
    
    2) 在Y's dealloc中

    - (void)dealloc {
       self.dealloced = self;
    }
    
    3) 在X中,Y的键路径也被解除分配

    [Y addObserver:self forKeyPath:@"dealloced" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL];
    
    4) 在X中,只需处理KVO更改以解除分配并取消注册所有文件

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    
        ...
        if ([keyPath isEqual:@"dealloced"]) {
           id obj = change[@"new"];
           [obj removeObserver:self forKeyPath:@"dealloced"];
           // remove other observing as well
        }
        ...
    }
    

    在X中,我们甚至不需要保持对Y的引用

    ,如果一个子对象正在观察父对象,那么这些子对象就不能保持对它的强引用了?子对象可以保持对父对象的强引用。只有当子对象作为父对象的子对象被删除时,如果子对象不释放对父对象的引用,它才会导致保留循环。确定,但当关系不会被删除并且应该在dealloc中删除时(但是dealloc永远不会被称为弧循环的原因)?如果希望子对象超出范围(不删除作为父项的子项的关系),首先解除子项的绑定。这将减少父项引用,允许其在适当时超出范围。删除关系是另一种操作
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    
        ...
        if ([keyPath isEqual:@"dealloced"]) {
           id obj = change[@"new"];
           [obj removeObserver:self forKeyPath:@"dealloced"];
           // remove other observing as well
        }
        ...
    }