【问题标题】:How to restrict NSNotification to call methods multiple times in iOS?如何限制 NSNotification 在 iOS 中多次调用方法?
【发布时间】:2018-03-10 07:45:37
【问题描述】:

我正在使用 NSNotificationCenter 在我的代码中发送本地通知,并在 Objective-C 和 Swift 中工作。我正在从 Objective-C 发布通知并在 Swift 中接收。但是我在通知中添加的方法被多次调用并仅在viewDidLoad 方法中添加了观察者。

斯威夫特:

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.serverCardSynced), name: NSNotification.Name(rawValue: NOTIF_SERVER_CARD_SYNCED), object: nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.checkForAutoSync), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.initateSync), name: NSNotification.Name(rawValue: NOTIF_CONTACT_ENTITY_CHANGE), object:nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.menuRemoved), name: NSNotification.Name(rawValue: NOTIF_MENU_REMOVED), object:nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.reloadAllCards(_:)), name: NSNotification.Name(rawValue: NOTIF_RELOAD_ALL_CARDS), object:nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.initateDownloadMyCards), name: NSNotification.Name(rawValue: NOTIF_DOWNLOAD_CARD), object:nil);
}

目标-C:

- (void)applicationDidBecomeActive:(UIApplication *)application {
    self.isSyncPending = true;
    [[NSNotificationCenter defaultCenter] 
    postNotificationName:NOTIF_CONTACT_ENTITY_CHANGE object:nil];
}

-(void)insertData(){
    [[NSNotificationCenter defaultCenter] 
    postNotificationName:NOTIF_SERVER_CARD_SYNCED object:nil];
}

我在deinit 中添加了删除观察者,但它甚至没有调用。如何停止多次调用。

【问题讨论】:

  • 移除视图中的观察者将消失
  • 我试过了,但它甚至没有调用那个特定的方法
  • 我也在应用程序中发布通知确实变得活跃,所以如何删除观察者,否则每次我来自后台时它都会调用多次

标签: ios objective-c swift nsnotificationcenter addobserver


【解决方案1】:
//call this method in viewDidLoad
fileprivate func registerNotifs() {

    //remove observer before adding to make sure that it is added only once

    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NOTIF_SERVER_CARD_SYNCED), object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NOTIF_CONTACT_ENTITY_CHANGE), object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NOTIF_MENU_REMOVED), object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NOTIF_RELOAD_ALL_CARDS), object: nil)
    NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: NOTIF_DOWNLOAD_CARD), object: nil)

    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.serverCardSynced), name: NSNotification.Name(rawValue: NOTIF_SERVER_CARD_SYNCED), object: nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.checkForAutoSync), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.initateSync), name: NSNotification.Name(rawValue: NOTIF_CONTACT_ENTITY_CHANGE), object:nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.menuRemoved), name: NSNotification.Name(rawValue: NOTIF_MENU_REMOVED), object:nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.reloadAllCards(_:)), name: NSNotification.Name(rawValue: NOTIF_RELOAD_ALL_CARDS), object:nil);
    NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.initateDownloadMyCards), name: NSNotification.Name(rawValue: NOTIF_DOWNLOAD_CARD), object:nil);
}

【讨论】:

    【解决方案2】:

    你可以这样做

    fileprivate func registerLocalNotifications() {
    
        NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.serverCardSynced), name: NSNotification.Name(rawValue: NOTIF_SERVER_CARD_SYNCED), object: nil)
        NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.checkForAutoSync), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
        NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.initateSync), name: NSNotification.Name(rawValue: NOTIF_CONTACT_ENTITY_CHANGE), object:nil)
        NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.menuRemoved), name: NSNotification.Name(rawValue: NOTIF_MENU_REMOVED), object:nil)
        NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.reloadAllCards(_:)), name: NSNotification.Name(rawValue: NOTIF_RELOAD_ALL_CARDS), object:nil)
        NotificationCenter.default.addObserver(self, selector:#selector(MainScreen.initateDownloadMyCards), name: NSNotification.Name(rawValue: NOTIF_DOWNLOAD_CARD), object:nil)
    }
    

    viewDidLoad

    中添加上述方法
    deinit {
            NotificationCenter.default.removeObserver(self)
    }
    

    参考:Where to remove observer for NSNotification in Swift?

    更新:

    检查你的类实例是否已经存在,即 实例化此视图控制器时在视图中 你可以这样做

    if let vc = yourNotificationViewCointrollerObj {
        // USE EXISTING ONE
    } else {
        // CREATE NEW INSTANCE
    }
    

    【讨论】:

    • 当对象解除分配时,观察者将被删除,根据最佳实践 IMO
    • 这意味着@iVj 您的代码正在创建多个对象,因此在内存中之前创建的对象仍然存在。
    • @AbhishekThapliyal 是的
    • 你在哪个类中调用这个视图控件,即主屏幕一个
    • 在主屏幕本身
    【解决方案3】:

    NSNotificationCenter 是一种“发布-订阅”机制,其中每个发布的通知都会传递给所有订阅者(称为观察者)。如果您多次收到通知,则意味着您有多个订阅者,或者您正在多次发送通知。

    我假设每种通知类型只有一个订阅者——Swift 中的 MainScreen UIViewController。这意味着您可能多次发送每个通知。

    例如,applicationDidBecomeActive 被多次调用(每次应用激活时)。如果您想在第一次之后停止回复此通知,您可以在第一次收到通知后立即退订:

    @objc
    func initateSync {
        // do something first time
        // ...
    
        // unsubscribe to not receive it anymore
        NotificationCenter.default.removeObserver(self,
            name: NSNotification.Name(rawValue: NOTIF_CONTACT_ENTITY_CHANGE),
            object: nil)    
    }
    

    这是你在收到不喜欢的报纸试用后在现实世界中所做的事情:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-19
      • 1970-01-01
      • 1970-01-01
      • 2020-11-20
      相关资源
      最近更新 更多