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

Swift:如何在viewDidLoad前完成委托设置?Firestore数据加载报错解决

问题解决思路

一、把parcelDataModel.vc = self放到viewDidLoad之前的可行方案

方案1:用懒加载初始化ViewModel

把var parcelDataModel = MainViewModel()改成懒加载形式,这样第一次访问parcelDataModel时,self已经完成初始化,能安全完成vc的赋值:

lazy var parcelDataModel: MainViewModel = {
    let model = MainViewModel()
    model.vc = self
    return model
}()

这样你就不用在viewDidLoad里重复写self.parcelDataModel.vc = self,且赋值会在viewDidLoad之前触发(首次访问model时,通常viewDidLoad里会调用它的方法,自然触发懒加载)。

方案2:在VC的初始化器里赋值

如果你的VC是代码初始化的,重写init(nibName:bundle:);如果是Storyboard/XIB创建的,重写init?(coder:):

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    self.parcelDataModel.vc = self
}

required init?(coder: NSCoder) {
    super.init(coder: coder)
    self.parcelDataModel.vc = self
}

注意:这种方式要确保parcelDataModel的初始化不依赖self的其他未初始化属性,你当前的parcelDataModel是默认初始化的,完全没问题。

二、重要提醒:避免循环引用

你的MainViewModel里的vc属性必须用弱引用,否则会导致VC和ViewModel互相持有,引发内存泄漏:

class MainViewModel {
    weak var vc: ParcelViewController? // 用weak修饰,设为可选类型
    // ...其他业务代码
}

三、顺便解决UITableView的nil解包错误

你遇到的表格数据nil解包问题,大概率是Firestore数据获取是异步操作,数据还没返回时表格就执行了数据源方法,或者ViewModel拿到数据后没通知VC刷新表格。

解决方法:

  1. 在MainViewModel的getCollectionData()方法中,数据获取完成后通知VC刷新表格:
// MainViewModel中的代码
func getCollectionData() {
    Firestore.firestore().collection("parcels").getDocuments { snapshot, error in
        // 解析数据并赋值给self.parcels
        self.parcels = ... // 你的数据解析逻辑
        // 回到主线程刷新表格
        DispatchQueue.main.async {
            self.vc?.parcelTable.reloadData()
        }
    }
}
  1. 在数据源方法中增加安全判断,避免数组越界:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = parcelTable.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ParcelTableViewCell
    guard indexPath.row < parcelDataModel.parcels.count else {
        return cell
    }
    let current = self.parcelDataModel.parcels[indexPath.row]
    cell.parcelTitleLabel.text = current.parcel_type
    cell.parcelImage.image = UIImage(named: current.parcel_img_url)
    cell.parcelWeightlabel.text = "\(current.parcel_min_weight)  -  \(current.parcel_max_weight)"
    cell.parcelDescriptionLabel.text = current.parcel_description
    return cell
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 05:42:40