在 Swift 中,在哪里删除 NSNotification 的观察者?

Where to remove observer for NSNotification in Swift?

由于 viewDidUnloaddealloc() 不可用,我应该在哪里删除 Swift 中 NSNotification 的观察者?

使用下面的方法,功能与dealloc相同。

deinit {
    // Release all resources
    // perform the deinitialization
}

A deinitializer is called immediately before a class instance is deallocated. You write deinitializers with the deinit keyword, similar to how intializers are written with the init keyword. Deinitializers are only available on class types.

Swift Deinitializer

Swift 提供了一个 deinit 方法,该方法在 类 的实例被销毁之前调用。

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Deinitialization.html

您可以使用三种方法:

  1. popViewController 之后,返回 navigationControllerdismissViewControllerAnimated

     deinit {
         print("Remove NotificationCenter Deinit")
         NSNotificationCenter.defaultCenter().removeObserver(self)
     }
    
  2. viewDidDisappear,已经是下一个view controller后移除:

     override func viewDidDisappear(animated: Bool) {
         NSNotificationCenter.defaultCenter().removeObserver(self)
     }
    
  3. viewWillDisappear - 打开下一个视图之前:

     override func viewWillDisappear(animated: Bool) {
         NSNotificationCenter.defaultCenter().removeObserver(self)
     }
    

Swift 5.0 语法:

NotificationCenter.default.removeObserver(self)

iOS 9(和 OS X 10.11)起,您不需要移除观察者 你自己,如果你不使用基于块的观察者的话。系统会为你做这件事,因为它在可能的情况下为观察者使用归零弱引用。

如果您正在使用基于块的观察者,请确保您 在闭包的捕获列表中使用 [weak self] 弱捕获自我,并删除观察者deinit 方法中。如果您不使用对自身的弱引用,deinit 方法(并因此删除该观察者)将永远不会被调用,因为通知中心将无限期地持有对它的强引用。

可在 Foundation Release Notes for OS X v10.11 and iOS 9 找到更多信息。

If the observer is able to be stored as a zeroing-weak reference the underlying storage will store the observer as a zeroing weak reference, alternatively if the object cannot be stored weakly (i.e. it has a custom retain/release mechanism that would prevent the runtime from being able to store the object weakly) it will store the object as a non-weak zeroing reference. This means that observers are not required to un-register in their deallocation method.

Block based observers via the -[NSNotificationCenter addObserverForName: object: queue: usingBlock] method still need to be un-registered when no longer in use since the system still holds a strong reference to these observers.

我还想指出,你应该使用这个方法:

func addObserver(_ observer: Any, selector aSelector: Selector, name aName: NSNotification.Name?, object anObject: Any?)

而不是

func addObserver(forName name: NSNotification.Name?, object obj: Any?, queue: OperationQueue?, using block: @escaping (Notification) -> Void) -> NSObjectProtocol

后者不会移除观察者(运行最近陷入这个问题)。如果您使用 iOS9,前者将删除观察者。

如果您在 viewWillAppear() 中添加您的观察者并在 viewWillDisappear()

中删除它们也很好

在 Swift 4.2 中,这是您可以删除观察者的方法之一

deinit {
    NotificationCenter.default.removeObserver(self, name: Notification.Name.Identifier, object: nil)
}

在 viewDidLoad 中设置 addObserver 通知 class

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(didReceivedItemDetail), name: Notification.Name.Identifier, object: nil)
}
deinit {
    NotificationCenter.default.removeObserver(self)
}

Swift 5

我有一个聊天应用程序,所以每当我从 ChatLogViewController 转到其他 viewController 然后再回来时,我的键盘通知都会有 1 个额外的 Observer。要删除它,我会在更改 viewController 或从我的 chatLogViewController.

中消失时删除所有观察者
override func viewDidDisappear(_ animated: Bool) {    
    super.viewDidDisappear(animated)

    NotificationCenter.default.removeObserver(self)
}