Objective-C 删除某个通知的所有观察者

Posted

技术标签:

【中文标题】Objective-C 删除某个通知的所有观察者【英文标题】:Objective-C remove all oberservers for a certain notification 【发布时间】:2013-07-17 21:16:24 【问题描述】:

我有一个 iPad 应用程序,它使用一个专有的库对象,它注册了一个“UIScreenDidConnectNotification”。有时,该对象在幕后被解除分配和重新分配。因为它在图书馆中,所以我无法确保它正确地删除了这个观察者。

有没有办法让我手动删除特定通知(即 UIScreenDidConnectNotification)的所有/任何观察者,而无需访问已注册的对象。这将阻止应用程序将消息发送到已释放的对象。

更新:这是解决我的问题的最简单方法。我希望我能做得更好,但生命太短暂了。 #进口 #导入

@interface NSNotificationCenter (AllObservers)
@end

@implementation NSNotificationCenter (AllObservers)

// This function runs before main to swap in our special version of addObserver
+ (void) load

    Method original, swizzled;
    original = class_getInstanceMethod(self, @selector(addObserver:selector:name:object:));
    swizzled = class_getInstanceMethod(self, @selector(swizzled_addObserver:selector:name:object:));

    method_exchangeImplementations(original, swizzled);


// This function runs before main to swap in our special version of addObserver
+ (void) load

    Method original, swizzled;
    original = class_getInstanceMethod(self, @selector(addObserver:selector:name:object:));
    swizzled = class_getInstanceMethod(self, @selector(swizzled_addObserver:selector:name:object:));

    method_exchangeImplementations(original, swizzled);


/*
    Use this function to remove any unwieldy behavior for adding observers
 */
- (void) swizzled_addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(id)notificationSender

    NSString *notification = [[NSString alloc] initWithUTF8String: "UIScreenDidConnectNotification" ];

    // It's a hack, but I just won't allow my app to add this type of notificiation
    if([notificationName isEqualToString: notification])
    
        printf("### screen notifcation added for an observer: %s\n", [notificationSender UTF8String] );
    
    else
    
        // Calls the original addObserver function
        [self swizzled_addObserver:notificationObserver selector:notificationSelector name:notificationName object:notificationSender];
       

【问题讨论】:

【参考方案1】:

由于它在库中,我无法确保它正确地移除了这个观察者。

如果对象是在库中创建的,则删除该对象不是您的责任。如果库在释放对象时未将其从通知中心移除,那么这显然是库中的错误。

有没有办法让我手动删除特定通知的所有/任何观察者...而无需访问已注册的对象。

NSNotificationCenter 的 API 中没有任何内容可以让您这样做。恰恰相反,事实上——让你删除观察者的方法都需要一个指向特定对象的指针。

【讨论】:

你是对的,没有 API 方法可以做到这一点。有一天,我可能会想出一个更好的解决方案,而不是调整 addObserver 方法以不响应 UIScreenDidConnectNotification【参考方案2】:

我同意 Caleb 的两点:执行此任务不是您的责任,而且 API 中没有任何内容可以支持它。

但是...如果您出于某种原因想要破解某些东西来执行此任务,请参阅此线程:How to retrieve all NSNotificationCenter observers?

该线程的选定答案具有NSNotificationCenter 的类别,允许您检索给定通知名称的所有观察者。同样,不建议这样做。

【讨论】:

这听起来像是我至少会尝试做的。谢谢! @Caleb 我同意这是图书馆的责任,我希望不要把它放在我的肩上来解决他们的错误。我迫不及待地等待可能永远不会到来的更新。我认为对象被取消/重新分配是我们的错。然而,我已经在代码中苦苦挣扎了将近一周,试图找出这种暴行发生在哪里。 请确保您不会意外删除您不打算删除的观察者,因为我确信这会产生各种奇怪的错误,追踪起来会很有趣:) 这是我最关心的问题。我希望我可以使用它来以某种方式追踪该特定对象并仅删除它的观察者。今天剩下的时间我在工作中度过了一些有趣的时光。如果我让它工作得更好,我会尝试发布代码以供参考。

以上是关于Objective-C 删除某个通知的所有观察者的主要内容,如果未能解决你的问题,请参考以下文章

iOS设计模式2 - 观察者模式_通知机制

Objective-c中如何基于uiswitch ON/OFF案例实现删除和重新调度本地通知

vue中的观察者模式和发布订阅者模式

KVO深入理解

KVO的实现原理

通过 CKSubscription 观察 CKRecord 删除不起作用