You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中接收Notification时是否需要使用weak self?

关于NotificationCenter回调中是否需要使用[weak self]的解惑

我在项目中发送并接收通知,无论是否使用weak self,应用均能正常运行,因此我对是否需要使用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],原因如下:

  1. 防止循环引用引发内存泄漏
    当闭包中直接用self(不加weak)时,闭包会对ViewController实例产生强引用,而NotificationCenter会持有这个闭包直到观察者被移除。如果ViewController本该被销毁(比如窗口关闭),但闭包的强引用会把它“挂”在内存里,导致deinit永远不会执行——你写的那段deinit代码根本不会打印日志,内存泄漏就这么发生了。

  2. 运行正常不代表没有隐患
    现在应用没崩溃,是因为内存泄漏不会立刻触发问题,但长期运行会让内存占用持续升高,轻则拖慢应用,重则触发系统内存警告甚至崩溃。只有在ViewController销毁的场景下,才能暴露这个问题。

  3. 保证代码安全
    用[weak self]后,self变成可选值,当ViewController已经被销毁时,self?.titleUpdater(...)会安全跳过,不会访问已经释放的内存。如果不用weak,万一Notification在ViewController销毁后被触发,就可能出现野指针访问,导致不可预料的崩溃。

补充:完善你的观察者管理代码

你现在的代码里没看到observer变量的声明,需要在ViewController中添加一个属性来保存观察者实例,这样才能在deinit中正确移除:

class ViewController: NSViewController {
    private var observer: NSObjectProtocol? // 新增属性
    
    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)
            }
        }
        // ... 其他代码
    }
    
    deinit {
        if let unwrappedObserver = observer {
            print("worked for deinit!")
            NotificationCenter.default.removeObserver(unwrappedObserver)
        }
    }
}

这样配合[weak self],才能确保ViewController可以正常销毁,彻底避免内存泄漏问题。

内容的提问来源于stack exchange,提问作者swiftPunk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:35:22