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

macOS下Swift向Contacts添加联系人时崩溃问题排查

问题:macOS Ventura下使用Contacts框架添加联系人时崩溃

已配置Contacts访问权限、沙盒设置正确,执行官方示例代码保存联系人时崩溃,控制台报错如下:

2022-10-28 06:26:03.473439+0200 justCare[11808:992463] [api] Attempt to write notes by a pre-Fall-2022 app
2022-10-28 06:26:03.499714+0200 justCare[11808:992463] [plugin] CDX_AB_GetGroupCollectionPath: nil group
2022-10-28 06:26:03.499770+0200 justCare[11808:992463] [plugin] CDX_AB_GetGroupCollectionPath: nil group
2022-10-28 06:26:03.500823+0200 justCare[11808:992463] [ABCDContact] An ABCDRecord is being saved without having a container assignment. Assigning the contact to <CNCDContainer 0x600001f9bba0 ab>. Please remember to assign contacts to containers to avoid recurring container lookup and contact re-validation costs.

实现代码:

import AppKit
import Contacts

class ContactsClass {
    func addToContacts(
        lastName: String,
        firstName: String,
        birthDate: Date?,
        mail: String = "",
        phone1: String = "",
        phone2: String = "",
        mobile: String = "",
        street: String,
        city: String,
        postCode: String
    ) {
        // Create a mutable object to add to the contact
        let contact = CNMutableContact()
            
        contact.givenName = firstName
        contact.familyName = lastName
        
        if mail != "" {
            let homeEmail = CNLabeledValue(label: CNLabelHome, value: mail as NSString)
            contact.emailAddresses = [homeEmail]
        }
        
        contact.phoneNumbers = []
        if phone1 != "" {
            contact.phoneNumbers.append(CNLabeledValue(label: CNLabelPhoneNumberMain, value: CNPhoneNumber(stringValue: phone1)))
        }
        if phone2 != "" {
            contact.phoneNumbers.append(CNLabeledValue(label: CNLabelPhoneNumberMain, value: CNPhoneNumber(stringValue: phone2)))
        }
        if mobile != "" {
            contact.phoneNumbers.append(CNLabeledValue(label: CNLabelPhoneNumberMobile, value: CNPhoneNumber(stringValue: mobile)))
        }
        
        let homeAddress = CNMutablePostalAddress()
        homeAddress.street = street
        homeAddress.city = city
        homeAddress.postalCode = postCode
        contact.postalAddresses = [CNLabeledValue(label: CNLabelHome, value: homeAddress)]
        
        
        if birthDate != nil {
            let calendar = Calendar.current
            let dateComponents = calendar.dateComponents([.year,.month,.day], from: birthDate!)
            
            var birthday = DateComponents()
            birthday.day = dateComponents.day
            birthday.month = dateComponents.month
            birthday.year = dateComponents.year  // (Optional) Omit the year value for a yearless birthday
            contact.birthday = birthday
        }
        // Save the newly created contact
        let store = CNContactStore()
        let saveRequest = CNSaveRequest()
        saveRequest.add(contact, toContainerWithIdentifier: nil)
        do {
            try store.execute(saveRequest)
        } catch {
            print("Saving contact failed, error: \(error)")
            // Handle the error
        }
    }
}

开发环境:macOS Ventura、Xcode 14.0.1


解决方案

核心原因

报错中的关键提示是**"An ABCDRecord is being saved without having a container assignment"**。在macOS Ventura及后续版本中,Contacts框架要求必须明确指定联系人的存储容器,而你当前代码中saveRequest.add(contact, toContainerWithIdentifier: nil)传入了nil,导致系统自动查找容器时出现异常,进而引发崩溃。第一条报错"Attempt to write notes by a pre-Fall-2022 app"是系统兼容性提示,并非崩溃的直接原因。

修复步骤

  1. 获取默认容器ID:在保存联系人前,从CNContactStore中获取默认的容器标识符,避免传入nil。
  2. 替换保存逻辑:用获取到的容器ID替代nil,添加到保存请求中。

修改后的保存逻辑代码:

// Save the newly created contact
let store = CNContactStore()
// 获取默认容器ID
guard let defaultContainerID = store.defaultContainerIdentifier() else {
    print("无法获取默认容器")
    return
}
let saveRequest = CNSaveRequest()
// 使用默认容器ID替代nil
saveRequest.add(contact, toContainerWithIdentifier: defaultContainerID)
do {
    try store.execute(saveRequest)
} catch {
    print("Saving contact failed, error: \(error)")
    // Handle the error
}

额外优化点

  • 避免强制解包birthDate!,改用可选绑定提升代码安全性:
if let birthDate = birthDate {
    let calendar = Calendar.current
    let dateComponents = calendar.dateComponents([.year,.month,.day], from: birthDate)
    
    var birthday = DateComponents()
    birthday.day = dateComponents.day
    birthday.month = dateComponents.month
    birthday.year = dateComponents.year
    contact.birthday = birthday
}
  • 邮箱赋值无需转为NSString,直接使用String类型即可:
let homeEmail = CNLabeledValue(label: CNLabelHome, value: mail)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 17:55:15