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

为何非async方法调用在async函数内需添加await修饰?

问题:async方法里调用NotificationCenter.addObserver为啥被要求加await?

我之前一直这么写通知监听:

NotificationCenter.default.addObserver(self, selector: #selector(foo), name: UIApplication.didEnterBackgroundNotification, object: nil)

但把这段代码移到async方法里时,编译器突然要求给这行加await修饰——明明addObserver根本不是异步方法:

func setup() async {
    let importantStuff = await someTask()
    // 存储重要数据,初始化完成

    // 这行不加await就编译不过
    // 但addObserver根本不是async方法啊🤨
    await NotificationCenter.default.addObserver(self, selector: #selector(foo), name: UIApplication.didEnterBackgroundNotification, object: nil)

    // 但这么写就完全没问题
    listen()
}

func listen() {
    NotificationCenter.default.addObserver(self, selector: #selector(foo), name: UIApplication.didEnterBackgroundNotification, object: nil)
}

最简复现示例

下面的代码编译失败(编译器强制要求给addObserver调用加await):

class Test {
    
    func thisFailsToCompile() async {
        let stuff = try! await URLSession.shared.data(from: URL(string: "https://google.com")!)
        NotificationCenter.default.addObserver(self, selector: #selector(foo), name: UIApplication.didEnterBackgroundNotification, object: nil)
    }
    
    @objc func foo() {
        
    }
}
原因分析

这是Swift编译器的上下文推断bug:当你在async方法里执行过await操作(比如示例里的URLSession.data(from:)),编译器的状态机切换到“异步上下文”后,会错误地把后续所有同步方法调用判定为需要await,哪怕这个方法本身是同步的。

解决办法

几种简单的绕开方式:

  • 把addObserver调用放到单独的同步方法里(就像示例里的listen()),再在async方法里调用这个同步方法
  • 给NotificationCenter.default加显式类型标注,帮编译器纠正上下文判断:
    let nc: NotificationCenter = .default
    nc.addObserver(self, selector: #selector(foo), name: UIApplication.didEnterBackgroundNotification, object: nil)
    

这个bug在Swift的后续版本中已经被修复,升级到较新的Swift版本后,问题会自动消失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 13:55:20