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

NSKeyedArchiver保存数据失败:出现无法识别的选择器报错

解决NSKeyedArchiver保存Participant数组时的_SwiftValue encodeWithCoder:崩溃问题

嘿,这个问题我之前也碰到过!你遇到的这个报错,本质是NSKeyedArchiver在编码你的Participant对象时,碰到了一个不支持NSCoding协议的类型,导致无法完成编码操作。下面给你一步步解决的方案:

1. 确保Participant类完全遵循NSCoding协议

NSKeyedArchiver依赖NSCoding协议来编码/解码对象,所以你的Participant类必须满足两个核心条件:

  • 继承自NSObject(因为NSCoding是Objective-C协议,Swift类需要兼容OC运行时环境)
  • 实现init?(coder: NSCoder)解码方法,以及encode(with: NSCoder)编码方法,并且要覆盖所有需要持久化的属性。

举个完整的示例代码:

import Foundation

class Participant: NSObject, NSCoding {
    // 假设你的Participant包含这些属性
    var name: String
    var age: Int?
    var isActive: Bool
    
    // 自定义初始化方法
    init(name: String, age: Int?, isActive: Bool) {
        self.name = name
        self.age = age
        self.isActive = isActive
    }
    
    // MARK: - NSCoding 协议实现
    required init?(coder: NSCoder) {
        // 解码所有属性:可选类型用decodeObject,基础类型用对应decode方法
        name = coder.decodeObject(forKey: "name") as! String
        age = coder.decodeObject(forKey: "age") as? Int
        isActive = coder.decodeBool(forKey: "isActive")
    }
    
    func encode(with coder: NSCoder) {
        // 编码所有属性:Swift基础类型会自动桥接OC类型,可选类型也可直接编码
        coder.encode(name, forKey: "name")
        coder.encode(age, forKey: "age")
        coder.encode(isActive, forKey: "isActive")
    }
}

2. 检查Participant的所有属性类型

如果Participant里包含自定义类型(比如枚举、其他自定义类),这些类型也必须支持NSCoding:

  • 对于枚举:如果是RawRepresentable类型(比如基于String/Int的枚举),可以编码它的rawValue,解码时再转成枚举值。示例:
enum ParticipantRole: String {
    case leader, member
}

// 在Participant的encode方法里
coder.encode(role.rawValue, forKey: "role")

// 在init?(coder:)方法里
guard let roleRaw = coder.decodeObject(forKey: "role") as? String,
      let role = ParticipantRole(rawValue: roleRaw) else {
    return nil
}
self.role = role
  • 对于其他自定义类:同样要让它继承NSObject并遵循NSCoding协议。

3. 确认数据源数组的正确性

删除UITableView行之后,确保你的数据源数组已经正确移除了对应的Participant对象,并且数组是纯粹的[Participant]类型,没有混入nil或其他不支持编码的类型。

4. 正确的保存/读取代码示例

最后,给你一个标准的保存和读取Participant数组的代码:

保存方法

func saveParticipants(_ participants: [Participant]) {
    // 获取Documents目录路径
    guard let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        print("无法获取Documents目录")
        return
    }
    let saveURL = docsDir.appendingPathComponent("participants_archive")
    
    do {
        let archiveData = try NSKeyedArchiver.archivedData(withRootObject: participants, requiringSecureCoding: false)
        try archiveData.write(to: saveURL)
        print("保存成功")
    } catch {
        print("保存失败:\(error.localizedDescription)")
    }
}

读取方法

func loadParticipants() -> [Participant]? {
    guard let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
        return nil
    }
    let saveURL = docsDir.appendingPathComponent("participants_archive")
    
    do {
        let archiveData = try Data(contentsOf: saveURL)
        guard let participants = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(archiveData) as? [Participant] else {
            return nil
        }
        return participants
    } catch {
        print("读取失败:\(error.localizedDescription)")
        return nil
    }
}

按照上面的步骤检查和修改,应该就能解决这个崩溃问题啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:03:34