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

将数据解归档为CNContact时发生崩溃问题求助

解归档CNContact时的崩溃问题解决方案

问题场景

将数据解归档为CNContact时触发崩溃,崩溃发生在以下代码行:

var decodedContacts = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [CNContact.self], from: archived) as? [CNContact?]

错误日志

NSKeyedUnarchiver.unarchivedObject(ofClasses: [CNContact.self], from: contactsData) as? [CNContact?] Error Domain=NSCocoaErrorDomain Code=4864 "value for key 'root' was of unexpected class 'NSArray' (0x1d97a9ed8) [/System/Library/Frameworks/CoreFoundation.framework]. Allowed classes are: {( "'CNContact' (0x1d9881018) [/System/Library/Frameworks/Contacts.framework]" )}" UserInfo={NSDebugDescription=value for key 'root' was of unexpected class Allowed classes are: {( "'CNContact' (0x1d9881018) [/System/Library/Frameworks/Contacts.framework]" )}}

关联代码实现

import Contacts

class ContactsManager {

static let numberOfSavedContacts = 12

static let shared = ContactsManager()
private init() {
    loadContacts()
}

private(set) var contacts: [CNContact?] = Array(repeating: nil, count: numberOfSavedContacts)

func add(contact: CNContact, at index: Int, phone: CNLabeledValue<CNPhoneNumber>? = nil) {
    if index < ContactsManager.numberOfSavedContacts {
        let editContact = contact.mutableCopy() as! CNMutableContact
        if phone != nil {
            editContact.phoneNumbers = [phone!]
        }
        contacts[index] = editContact
        saveContacts()
    }
}

func deleteContact(_ index: Int) {
    if index < ContactsManager.numberOfSavedContacts {
        contacts[index] = nil
        saveContacts()
    }
}

func saveContacts() {
    do {
        let contactsData = try NSKeyedArchiver.archivedData(withRootObject:contacts,requiringSecureCoding:false)
        UserDefaults.standard.set(contactsData, forKey: "contacts")
    }
    catch {
        print(error)
    }
}


func loadContacts() {
    if let contactsData = UserDefaults.standard.object(forKey: "contacts") as? Data {
        do {
            if var decodedContacts = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, CNContact.self, NSNull.self], from: contactsData) as? [CNContact?] {
                print(decodedContacts)
                contacts = decodedContacts
            } else {
                print("decodedContacts is nil")
            }
        } catch {
            print(error)
        }
    }
}
}

解决方法

崩溃核心原因是解归档时未允许根对象类型(NSArray),同时数组包含nil元素,归档时nil会被转为NSNull,因此也需要允许该类型。

修改解归档代码,确保ofClasses参数包含所有必需类型:

// 正确的解归档写法
if var decodedContacts = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, CNContact.self, NSNull.self], from: contactsData) as? [CNContact?] {
    contacts = decodedContacts
}

额外注意事项:

  • 你归档的根对象是[CNContact?]类型的数组,对应OC的NSArray,必须将其加入允许类列表
  • 数组中的nil会被序列化为NSNull,所以要把NSNull.self也加入允许类
  • 如果之前用错误的类列表归档过数据,建议清理旧的UserDefaults缓存,避免解归档冲突

你的loadContacts方法中已经写了正确的允许类列表,但崩溃的代码行仅传入了[CNContact.self],这是问题根源,确保所有解归档逻辑都使用正确的类列表即可解决崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 01:27:49