如何在Swift 5中使用addObserver闭包方法删除Observer

mm5n2pyu  于 2022-11-28  发布在  Swift
关注(0)|答案(2)|浏览(232)

这是我的第一篇文章。我是日本的iOS工程师(这个月刚刚成为)。
我在Swift 5中使用NotificationCenterremoveObserver方法时遇到问题。
我通过使用闭包类型addObserver将观察器添加到ViewController(VC)中。我希望在VC的取消初始化调用时删除此观察器。
我用VC的deinit方法编写了NotificationCenter.default.removeObserver(self)。但是,这似乎对我不起作用。
有什么问题吗???
此外,如果我的代码有内存泄漏问题,让我知道如何修复它。
这是我的一段代码。

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: nil) { [weak self] notification in

            guard let self = self else { return }
            self.loadWeather(notification.object)
        }
    }
    
    deinit {
        print(#function)
        print("ViewController died")

        NotificationCenter.default.removeObserver(self)
    }
}
bjg7j2ky

bjg7j2ky1#

Closure-based addObserver的名字

如果你使用addObserver的基于闭包的变体,标记(不是self)是观察者。通知中心在这种情况下对self一无所知。文档对此并不十分清楚。
from Twitter
意思是这样做毫无意义:NotificationCenter.default.removeObserver(self)
docs推荐两种方式:

正常方式

像平常一样订阅:

let center = NSNotificationCenter.defaultCenter()
let mainQueue = NSOperationQueue.mainQueue()
self.localeChangeObserver = center.addObserverForName(NSCurrentLocaleDidChangeNotification, object: nil, queue: mainQueue) { (note) in
    print("The user's locale changed to: \(NSLocale.currentLocale().localeIdentifier)")
}

在代码的某个位置删除观察器。NotificationCenter.default.removeObserver(self.localeChangeObserver),例如通过函数或在deinit
注意:您仍然需要使用[weak self]来避免保留周期。
为了避免保留循环,当self包含观察者作为强引用时,在块内使用对self的弱引用。

单个订阅

在观察器第一次收到回调后立即删除它

let center = NSNotificationCenter.defaultCenter()
let mainQueue = NSOperationQueue.mainQueue()
var token: NSObjectProtocol?
token = center.addObserverForName("OneTimeNotification", object: nil, queue: mainQueue) { (note) in
    print("Received the notification!")
    center.removeObserver(token!)
}

Selector-based addObserver的名字

如果您使用基于选择器的添加,self(没有标记)观察器。尽管如此,您应该避免执行以下操作:

NotificationCenter.default.removeObserver(self)

因为您的代码可能不是添加观察器时涉及对象的唯一代码。删除观察器时,请尽可能使用最具体的详细信息来删除它。例如,如果使用名称和对象来注册观察器,请使用带有名称和对象的removeObserver(_:name:object:)
只有在deinit方法中调用removeObserver(something)才是安全的,除此之外,不要使用它,而是使用removeObserver(_:name:object:)
deinit之外调用removeObserver(self)是不正确的,因为你会删除所有为该对象设置的观察值。在deinit之内调用它不是不正确的,但是没有意义,因为该对象会被立即释放。

xqnpmsa8

xqnpmsa82#

将观察器对象设置为当前视图控制器。
apple doc.s,对象为
观察器希望接收其通知的对象;也就是说,只有此发送者发送的通知才会传递给观察者。

NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification,
                                       object: self,
                                       queue: nil) { [weak self] notification in
    guard let self = self else { return }
    self.loadWeather(notification.object)
}

正在从NotificationCenter移除观察者

deinit {
    NotificationCenter.default.removeObserver(self)
}

"另一种方式"
您也可以复制Notification Observer对象,并将其从deinit中的NotificationCenter中删除。

let notificationCenter = NotificationCenter.default
var loadWeatherObserver: NSObjectProtocol?

override func viewDidLoad() {
    super.viewDidLoad()
    loadWeatherObserver = notificationCenter.addObserver(forName: UIApplication.didBecomeActiveNotification,
                                                         object: nil,
                                                         queue: nil) { [weak self] notification in
        guard let self = self else { return }
        self.loadWeather(notification.object)
    }
}

deinit {
    if (loadWeatherObserver != nil) {
        notificationCenter.removeObserver(loadWeatherObserver!)
    }
}

相关问题