[英]Should I use weak self when I getting new Notification in swift?
我正在发出通知并且我也收到通知并且应用程序可以运行,我的应用程序可以在有或没有weak self
的情况下工作所以我对使用或不使用它有点困惑,也许有人可以帮助我并告诉我如果我需要weak self
以及为什么我需要它或为什么我在这里不需要它。
此代码适用于 macOS Storyboard Cocoa 项目。
import Cocoa
import SwiftUI
var appName: String = "My App Name"
class ViewController: NSViewController {
override func viewWillAppear() {
NotificationCenter.default.addObserver(forName: myNotificationName, object: nil, queue: .main) { [weak self] newNotification in
if let unwrappedNewNotification = newNotification.object as? String {
self?.titleUpdater(value: unwrappedNewNotification)
}
}
let controller = NSHostingController(rootView: ContentView())
self.view = controller.view
self.view.window?.title = appName
}
private func titleUpdater(value: String) {
appName = value
self.view.window?.title = value
}
}
struct ContentView: View {
var body: some View {
VStack {
Button("Change", action: {
postMyNotification(value: appName + " updated!")
})
}
.frame(width: 400.0, height: 300.0)
}
}
let myNotificationName: Notification.Name = Notification.Name(rawValue: "myNotificationName")
func postMyNotification(value: String) {
NotificationCenter.default.post(Notification(name: myNotificationName, object: value))
}
更新:
deinit {
if let unwrappedObserver: NSObjectProtocol = observer {
print("worked for deinit!")
NotificationCenter.default.removeObserver(unwrappedObserver)
}
}
是的,在这种情况下你应该使用weak self
,因为NotificationCenter
必须强烈地坚持闭包。 如果你不使用weak self
,你的ViewController
永远不会被破坏。
但是你还应该确保当ViewController
被销毁时你的观察者也被销毁。 addObserver(forName:object:queue:using:)
方法返回一个 object ,您应该将其保存在实例属性中并传递给deinit
中的NotificationCenter.default.removeObserver
。
class ViewController: NSViewController {
private var observer: NSObjectProtocol? = nil
deinit {
if let observer {
NotificationCenter.default.removeObserver(observer)
}
}
override func viewWillAppear() {
observer = NotificationCenter.default.addObserver(forName: myNotificationName, object: nil, queue: .main) { [weak self] newNotification in
if let unwrappedNewNotification = newNotification.object as? String {
self?.titleUpdater(value: unwrappedNewNotification)
}
}
let controller = NSHostingController(rootView: ContentView())
self.view = controller.view
self.view.window?.title = appName
}
private func titleUpdater(value: String) {
appName = value
self.view.window?.title = value
}
}
但我建议使用不同的 API,这样您就不必编写deinit
。 改为使用 Combine,如下所示:
import Combine
import SwiftUI
class ViewController: NSViewController {
private var tickets: [AnyCancellable] = []
override func viewWillAppear() {
NotificationCenter.default.publisher(for: myNotificationName)
.receive(on: DispatchQueue.main)
.sink { [weak self] in
if let self, let newTitle = $0.object as? String {
self.titleUpdater(value: newTitle)
}
}
.store(in: &tickets)
let controller = NSHostingController(rootView: ContentView())
self.view = controller.view
self.view.window?.title = appName
}
private func titleUpdater(value: String) {
appName = value
self.view.window?.title = value
}
}
这样,您就不必编写deinit
。 当ViewController
被销毁时,它会自动销毁其实例属性,包括tickets
数组及其内容。 当sink
返回的票证( AnyCancellable
)被销毁时,它取消订阅。
您甚至可以完全消除对self
的使用。 您没有显示appName
的声明。 如果它是全球性的,您可以这样订阅:
NotificationCenter.default.publisher(for: myNotificationName)
.receive(on: DispatchQueue.main)
.sink { [view] in
if let newTitle = $0.object as? String {
appName = newTitle
view.window?.title = newTitle
}
}
.store(in: &tickets)
现在闭包直接捕获view
而不是捕获self
,所以不存在保留循环的可能性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.