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

从UserDefaults解码JSON数据赋值数组时App崩溃求助

崩溃原因分析

1. 单例初始化递归调用(直接崩溃原因)

在CreatedPlayers的私有初始化方法中,你调用了CreatedPlayers.loadPlayers(),而loadPlayers内部会调用AddPlayer方法,AddPlayer中又访问了shared.players。

由于shared是静态存储属性,其初始化是懒加载的——当第一次访问shared时才会执行CreatedPlayers()创建实例。但在实例的init方法执行过程中,还未完成实例创建与shared的赋值,此时AddPlayer访问shared会再次触发单例初始化,形成无限递归初始化,最终触发EXC_BREAKPOINT崩溃。

2. 额外的不良设计(加剧问题)

  • players数组的didSet会在每次修改时调用savePlayers,当loadPlayers循环添加玩家时,每添加一个就会触发一次保存操作,不仅效率低下,还会在初始化过程中增加递归复杂度。
  • 手动解析JSON完全没必要,Player已实现Codable协议,直接用JSONDecoder解码更可靠,手动解析容易引入额外错误。
修复方案

方案1:调整初始化顺序,避免递归

修改CreatedPlayers的初始化逻辑,不在init中直接调用loadPlayers,而是在单例初始化完成后再加载数据:

class CreatedPlayers {
    static var shared = CreatedPlayers()
    
    var players: [Player] = [] {
        didSet {
            CreatedPlayers.savePlayers()
        }
    }
    
    private init(players: [Player] = []) {
        self.players = players
        // 移除init中的loadPlayers调用
    }
    
    // 添加初始化完成后调用的加载方法
    static func initialize() {
        loadPlayers()
    }
    
    // 恢复最初的Codable解码逻辑
    static func loadPlayers() {
        guard let encodedData = UserDefaults.standard.data(forKey: "createdPlayers") else {
            print("No data found for key 'createdPlayers'")
            return
        }
        do {
            shared.players = try JSONDecoder().decode([Player].self, from: encodedData)
        } catch {
            print("Error decoding players: \(error.localizedDescription)")
        }
    }
    
    // 其余代码保持不变...
}

然后在App启动时(比如AppDelegate的didFinishLaunchingWithOptions或SceneDelegate的sceneDidBecomeActive中)调用:

CreatedPlayers.initialize()

方案2:改用惰性加载加载数据(更简洁)

直接在players的初始化中加载数据,利用Swift惰性初始化特性,避免触发didSet(初始化赋值不会触发didSet):

class CreatedPlayers {
    static var shared = CreatedPlayers()
    
    var players: [Player] = {
        guard let encodedData = UserDefaults.standard.data(forKey: "createdPlayers") else {
            return []
        }
        do {
            return try JSONDecoder().decode([Player].self, from: encodedData)
        } catch {
            print("Error decoding players: \(error.localizedDescription)")
            return []
        }
    }() {
        didSet {
            CreatedPlayers.savePlayers()
        }
    }
    
    private init() {}
    
    // 移除原来的loadPlayers方法,其余代码保持不变...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 19:40:34