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

Swift开发:ObservableObject收藏类数据加载保存实现及崩溃解决

收藏功能实现与崩溃修复方案

一、崩溃核心诱因定位

对应你现有代码的崩溃问题,可先排查以下几个直接触发崩溃的代码缺陷:

  • 方法返回值缺失:你定义的add、remove方法标注了返回值为Bool,但函数内部没有任何返回语句,运行到这两个方法时会触发运行时崩溃
  • 类型转换无安全校验:未做加载逻辑的前提下,如果后续直接对UserDefaults取出的值做强制类型转换,类型不匹配时会直接触发崩溃
  • 依赖注入不完整:如果favorites实例没有通过@StateObject正确初始化、并通过.environmentObject注入到视图层级,按钮触发时调用未实例化的空对象会触发野指针崩溃
  • 可选值强解包失败:如果传入的sclocations是隐式解包可选类型,当上层传值为nil时,按钮触发访问该值会直接崩溃

二、补全Favorites类的本地加载与写入逻辑

本实现使用系统自带的UserDefaults做轻量本地持久化,适配你当前存储收藏ID集合的需求,无额外依赖:

修正后的完整Favorites实现

class Favorites: ObservableObject {
    // 存储收藏位置的ID集合
    private var task: Set<Int>
    // 本地存储的键值标识
    private let saveKey = "Favorites"

    init() {
        // 加载本地存储的收藏数据,做类型安全校验
        if let savedFavoriteIDs = UserDefaults.standard.array(forKey: saveKey) as? [Int] {
            self.task = Set(savedFavoriteIDs)
        } else {
            // 无历史存储数据时初始化空集合
            self.task = []
        }
    }

    func contains(_ sclocations: SClocation) -> Bool {
        task.contains(sclocations.id)
    }

    // 移除原有多余的Bool返回值,避免无返回值引发的崩溃
    func add(_ sclocations: SClocation) {
        objectWillChange.send()
        task.insert(sclocations.id)
        save()
    }

    func remove(_ sclocations: SClocation) {
        objectWillChange.send()
        task.remove(sclocations.id)
        save()
    }

    func save() {
        // 将Set转成UserDefaults支持的数组类型完成本地写入
        UserDefaults.standard.set(Array(task), forKey: saveKey)
    }
}

逻辑说明

  • 加载逻辑:UserDefaults不直接支持Set类型,因此读取时先将存储值转为[Int]数组,再转换为Set结构,全程使用as?做安全类型校验,避免强制转换引发的崩溃
  • 写入逻辑:将内存中的Set结构转换为数组格式,写入UserDefaults对应的键值下,完成持久化
  • 方法修正:删除了原add、remove方法不必要的Bool返回值,从根源上解决漏写return语句引发的运行时崩溃

三、按钮逻辑的崩溃排查优化

你原有的按钮代码逻辑本身没有问题,但可调整为更安全的写法,减少重复方法调用引发的异常:

Button {
    // 触发逻辑判断
    if favorites.contains(sclocations) {
        favorites.remove(sclocations)
    } else {
        favorites.add(sclocations)
    }
} label: {
    // 按钮文案单独提取,减少重复逻辑
    Text(favorites.contains(sclocations) ? "Remove from Favorites" : "Add to Favorites")
}

同时需要确认视图层级的依赖注入正确性:

  • 持有视图的上层页面必须通过@StateObject初始化Favorites实例,不能在子视图中临时实例化
  • 初始化完成后必须通过.environmentObject(favorites)修饰符将实例注入到子视图层级,子视图中通过@EnvironmentObject获取的favorites实例才能正常工作,避免空实例调用引发的崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 13:06:02