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"是系统兼容性提示,并非崩溃的直接原因。
修复步骤
- 获取默认容器ID:在保存联系人前,从
CNContactStore中获取默认的容器标识符,避免传入nil。 - 替换保存逻辑:用获取到的容器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
相关产品推荐
相关产品推荐

