gpt4 book ai didi

Cocoa绑定(bind)和KVO,注销观察者,当观察对象获取 `dealloced`时

转载 作者:行者123 更新时间:2023-12-03 16:07:35 25 4
gpt4 key购买 nike

当观察对象被解除分配时,我如何取消注册观察者?

当观察到的对象被释放时,cocoa 绑定(bind)如何处理这种情况?

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

最佳答案

2017 年更新

正如 @GregBrown 在评论中指出的那样,2013 年的原始答案在 2017 年不起作用。我假设原始答案在 2013 年确实有效,因为我的做法是不经过测试就回答,但是我不再使用任何代码。

那么2017年你是如何解决这个问题的呢?最简单的答案是混合,有些人会发现这是矛盾的,但在使用 block 时却不一定如此。下面是一个快速的概念验证,其中包含以下注意事项:

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

  • 效率不是考虑因素!例如,您可能希望混合 dealloc每个类一次,并在每个实例关联对象中保留观察者/键路径列表。

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

代码:

@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

__unsafe_unretained 的两种用途是为了解决 ARC 的后果。特别是方法通常保留其 self参数,dealloc方法则不然, block 遵循相同的按需保留模型。使用 block 作为 dealloc 的实现这种行为需要被覆盖,这就是 __unsafe_unretained正在被用于。

要使用上面的代码,您只需替换:

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

与:

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

考虑到上述注意事项,上述代码将在 2017 年完成工作(不能保证 future 几年!)

2013 年原始答案

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

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

使用关联对象,您可以安排在观察对象被释放时自动删除观察者。设 X 为观察者,Y 为被观察对象。

创建一个“取消注册”类,例如 Z,它采用(通过 init)X 和 Y 并在其 dealloc 中方法removeObserver .

要设置观察,X:

  1. 创建 Z 的实例,并传递其自身和 Y。
  2. 将自己注册为 Y 的观察员。
  3. 将 Z 与 Y 关联起来。

现在,当 Y 被释放时,Z 也将被释放,这将导致 Z 的 dealloc被调用并取消注册 X 的观察。

如果您需要在 Y 仍处于事件状态时删除对 X 的观察,您可以通过删除关联的对象来完成此操作 - 这样做将触发其 dealloc ...

只要您想在另一个对象被释放时触发某些操作,就可以使用此模式。

HTH

关于Cocoa绑定(bind)和KVO,注销观察者,当观察对象获取 `dealloced`时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20101558/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com