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

iOS开发:初始化TableView数据源数组调用UserDefaults报错的解决

解决Swift属性初始化器无法访问实例成员的问题

问题场景

开发App天气功能时,通过Visual Crossing API获取数据,在didUpdateWeather函数中将数据存入UserDefaults:

let date1ForTableView = UserDefaults.standard

func didUpdateWeather(weather: WeatherModel) {
    DispatchQueue.main.async {
        self.date1ForTableView.set(weather.datetime1, forKey: "Date1")
        // ...其他代码
    }
}

但初始化TableView数据源数组WeatherForecastCells时,出现错误:

Cannot use instance member 'date1ForTableView' within property initialiser; property initialisers run before 'self' is available

初始化代码如下:

var WeatherForecastCells: [WeatherCell] = [
    WeatherCell(image: "", date: date1ForTableView.string(forKey: "Date1")!, low: "18°", high: "31°"),
    // ...其他元素
]

已知定位输入后数据会自动保存,附TableView数据源扩展代码:

extension WeatherFeatures: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return WeatherForecastCells.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "WeatherCellsForWeatherFeature", for: indexPath) as! WeatherForecastTableViewCell
        
        cell.WeatherDetails.text = "\(WeatherForecastCells[indexPath.row].date) - Low: \(WeatherForecastCells[indexPath.row].low) High: \(WeatherForecastCells[indexPath.row].high)"
        
        return cell
    }
}

解决方案

1. 直接使用UserDefaults.standard初始化数组

既然date1ForTableView只是UserDefaults.standard的实例引用,完全可以跳过这个变量,直接在数组初始化时调用UserDefaults.standard,绕过实例成员访问限制:

var WeatherForecastCells: [WeatherCell] = [
    WeatherCell(image: "", date: UserDefaults.standard.string(forKey: "Date1")!, low: "18°", high: "31°"),
    // ...其他元素
]

这是最直接的解决方式,不需要修改其他代码结构。

2. 用懒加载延迟数组初始化

将WeatherForecastCells声明为lazy属性,这样初始化逻辑会推迟到第一次访问该属性时执行,此时self已经完全初始化:

lazy var WeatherForecastCells: [WeatherCell] = [
    WeatherCell(image: "", date: date1ForTableView.string(forKey: "Date1")!, low: "18°", high: "31°"),
    // ...其他元素
]

注意:懒加载属性默认线程不安全,UI场景下主线程访问无需额外处理;如果后续要更新数据,需要重新赋值数组并刷新TableView。

3. 声明可选数组,在viewDidLoad或数据更新时初始化

把数组改成可选类型,在viewDidLoad(或数据回调后)完成初始化,确保self可用:

var WeatherForecastCells: [WeatherCell]?

override func viewDidLoad() {
    super.viewDidLoad()
    // 初始化数据源数组
    WeatherForecastCells = [
        WeatherCell(image: "", date: date1ForTableView.string(forKey: "Date1")!, low: "18°", high: "31°"),
        // ...其他元素
    ]
    tableView.reloadData()
}

同时需要修改数据源方法,处理可选值避免崩溃:

extension WeatherFeatures: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return WeatherForecastCells?.count ?? 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "WeatherCellsForWeatherFeature", for: indexPath) as! WeatherForecastTableViewCell
        
        guard let cellData = WeatherForecastCells?[indexPath.row] else {
            return cell
        }
        cell.WeatherDetails.text = "\(cellData.date) - Low: \(cellData.low) High: \(cellData.high)"
        
        return cell
    }
}

4. 数据更新后刷新数据源

无论用哪种方案,当didUpdateWeather中保存完新数据后,都需要重新初始化数组并刷新TableView,确保界面显示最新数据:

func didUpdateWeather(weather: WeatherModel) {
    DispatchQueue.main.async {
        self.date1ForTableView.set(weather.datetime1, forKey: "Date1")
        // 重新初始化数据源数组
        self.WeatherForecastCells = [
            WeatherCell(image: "", date: self.date1ForTableView.string(forKey: "Date1")!, low: "18°", high: "31°"),
            // ...其他元素
        ]
        self.tableView.reloadData()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 20:05:03