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

Swift中viewWillAppear赋值后变量仍为nil的问题排查与解决

Swift async/await异步赋值后tableView中变量为nil的原因及解决方法

问题描述

我是Swift async/await的新手,尝试在MyViewController的viewWillAppear中调用异步函数为全局变量job赋值。在异步函数内部job能获取到值,但在tableView的cellForRowAt方法中给cell属性传值时,job却为nil。

示例代码

class MyViewController: UIViewController {
  private var job: Job!

  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    Task { [weak self] in
      await self?.getJob()
    }
  }
  

   private func getJob() async {
    job = await viewModel.getJob(byID: "xxxxxxx") // will return a Job Object
    // more code...
    print(job) // it's ok 
  }

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    
    print(job) // it is nil!!!
  }
}

原因分析

  • 异步时序不匹配:viewWillAppear中启动的Task是异步执行的,await viewModel.getJob(byID:)需要等待异步任务(比如网络请求)完成才会给job赋值。但tableView的cellForRowAt会在视图加载完成后立即触发,此时job还未完成赋值,所以输出nil。
  • 隐式解包可选的初始状态:job被声明为Job!(隐式解包可选),初始值为nil。在异步赋值完成前访问它,会直接返回nil,甚至可能因强制解包引发崩溃。

解决方法

1. 赋值完成后主线程刷新tableView

异步任务完成并赋值job后,必须回到主线程刷新tableView,确保cell能获取到最新数据:

private func getJob() async {
    job = await viewModel.getJob(byID: "xxxxxxx")
    print(job)
    // 主线程刷新tableView
    DispatchQueue.main.async {
        self.tableView.reloadData()
    }
}

2. 替换隐式解包为普通可选类型

将job改为普通可选类型,避免隐式解包的风险,并在cellForRowAt中做安全校验:

// 修改变量声明
private var job: Job?

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellID", for: indexPath) as! YourCellType
    // 安全访问job
    if let job = job {
        // 给cell赋值
        cell.titleLabel.text = job.title
        // 其他配置...
    }
    return cell
}

3. 管理异步任务生命周期(可选)

为了避免视图消失后仍执行不必要的异步任务,可添加任务引用并在视图消失时取消:

private var jobFetchTask: Task<Void, Never>?

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // 取消之前未完成的任务
    jobFetchTask?.cancel()
    jobFetchTask = Task { [weak self] in
        await self?.getJob()
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    jobFetchTask?.cancel()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 04:06:25