英文:
swift update contact fails
问题
在我的应用程序中,我从客户那里收集数据,如姓名、地址、电话号码等。我想提供一个按钮,用于将这些数据保存并更新到苹果的联系人应用程序。
因此,我编写了这个类:
class ContactsClass {
func addToContacts(
lastName: String,
firstName: String,
mail: String = "",
phone1: String = "",
street: String,
city: String,
postCode: String
) {
// 创建一个可变对象以添加到联系人
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)))
}
let homeAddress = CNMutablePostalAddress()
homeAddress.street = street
homeAddress.city = city
homeAddress.postalCode = postCode
contact.postalAddresses = [CNLabeledValue(label: CNLabelHome, value: homeAddress)]
// 保存新创建的联系人
let store = CNContactStore()
let saveRequest = CNSaveRequest()
saveRequest.add(contact, toContainerWithIdentifier: gruppe)
do {
try store.execute(saveRequest)
} catch {
print("保存联系人失败,错误:\(error)")
// 处理错误
}
}
func checkForExistingContact(familyName: String, givenName: String) -> CNContact? {
let store = CNContactStore()
do {
let predicate = CNContact.predicateForContacts(matchingName: familyName)
let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactEmailAddressesKey] as [CNKeyDescriptor]
let contacts = try store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
for contact in contacts {
if contact.givenName == givenName {
return contact
}
}
return nil
} catch {
return nil
}
}
func updateContact(
contact: CNContact,
lastName: String,
firstName: String,
mail: String = "",
phone1: String = "",
street: String,
city: String,
postCode: String
) {
let mutableContact = contact.mutableCopy() as! CNMutableContact
mutableContact.givenName = firstName
mutableContact.familyName = lastName
if mail != "" {
let homeEmail = CNLabeledValue(label: CNLabelHome, value: mail as NSString)
mutableContact.emailAddresses = [homeEmail]
}
mutableContact.phoneNumbers = []
if phone1 != "" {
mutableContact.phoneNumbers.append(CNLabeledValue(label: CNLabelPhoneNumberMain, value: CNPhoneNumber(stringValue: phone1)))
}
let homeAddress = CNMutablePostalAddress()
homeAddress.street = street
homeAddress.city = city
homeAddress.postalCode = postCode
mutableContact.postalAddresses = [CNLabeledValue(label: CNLabelHome, value: homeAddress)]
// 保存已更新的联系人
let store = CNContactStore()
let saveRequest = CNSaveRequest()
saveRequest.update(mutableContact)
do {
try store.execute(saveRequest)
} catch {
print("保存联系人失败,错误:\(error)")
// 处理错误。
}
}
}
我的按钮调用了这个函数:
private func addToContacts() {
let con = ContactsClass()
if let contact = con.checkForExistingContact(familyName: klient.nachname!, givenName: klient.vorname!) {
con.updateContact(
contact: contact,
lastName: klient.nachname!,
firstName: klient.vorname!,
mail: klient.email ?? "",
phone1: klient.telefon1 ?? "",
street: selectedAddress?.strasse ?? "",
city: selectedAddress?.ort ?? "",
postCode: selectedAddress?.plz ?? ""
)
} else {
con.addToContacts(
lastName: klient.nachname!,
firstName: klient.vorname!,
mail: klient.email ?? "",
phone1: klient.telefon1 ?? "",
street: selectedAddress?.strasse ?? "",
city: selectedAddress?.ort ?? "",
postCode: selectedAddress?.plz ?? ""
)
}
}
我的问题:
- 添加联系人工作正常,没有问题。
- 更新这个联系人没有问题。
日志中的错误:
2023-06-21 21:28:25.166437+0200 justCare 2[64058:433979] [core] Attempted to register account monitor for types client is not authorized to access: {
"com.apple.account.CardDAV",
"com.apple.account.Exchange",
"com.apple.account.LDAP"
}
2023-06-21 21:28:25.166546+0200 justCare 2[64058:433979] [accounts] CNAccountCollectionUpdateWatcher 0x6000020a04c0: Store registration failed: Error Domain=com.apple.accounts Code=7 "(null)"
2023-06-21 21:28:25.166605+0200 justCare 2[64058:433979] [accounts] CNAccountCollectionUpdateWatcher 0x6000020a04c0: Update event received, but store registration failed. This event will be handled, but the behavior is undefined.
2023-06-21 21:28:25.340559+0200 justCare 2[64058:433979] [api] Attempt to read notes by an unentitled app
2023-06-21 21:28:25.343112+0200 justCare 2[64058:433979] [General] A property was not requested when contact was fetched.
2023-06-21 21:28:25.348149+0200 justCare 2[64058:433979] [General] (
0 CoreFoundation 0x000000019e1d3154 __exceptionPreprocess + 176
1 libobjc.A.dylib 0x000000019dcf24d4 objc_exception_throw + 60
2 CoreFoundation 0x000000019e1d2ff8 +[NSException exceptionWithName:reason:userInfo:] + 0
3 Contacts 0x00000001b16f23c4 -[CNMutableContact setPhoneNumbers:] + 328
4 justCare 2 0x0000000100a04e04 $s10justCare_213ContactsClassC13update
<details>
<summary>英文:</summary>
In my app, I collect data from clients like names, addresses, phone numbers etc. I'd like to offer a button for saving and updating these data to apple's contacts app.
Therefor I wrote this class:
class ContactsClass {
func addToContacts(
lastName: String,
firstName: String,
mail: String = "",
phone1: 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)))
}
let homeAddress = CNMutablePostalAddress()
homeAddress.street = street
homeAddress.city = city
homeAddress.postalCode = postCode
contact.postalAddresses = [CNLabeledValue(label: CNLabelHome, value: homeAddress)]
// Save the newly created contact
let store = CNContactStore()
let saveRequest = CNSaveRequest()
saveRequest.add(contact, toContainerWithIdentifier: gruppe)
do {
try store.execute(saveRequest)
} catch {
print("Saving contact failed, error: \(error)")
// Handle the error
}
}
func checkForExistingContact(familyName: String, givenName: String) -> CNContact? {
let store = CNContactStore()
do {
let predicate = CNContact.predicateForContacts(matchingName: familyName)
let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactEmailAddressesKey] as [CNKeyDescriptor]
let contacts = try store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
for contact in contacts {
if contact.givenName == givenName {
return contact
}
}
return nil
} catch {
return nil
}
}
func updateContact(
contact: CNContact,
lastName: String,
firstName: String,
mail: String = "",
phone1: String = "",
street: String,
city: String,
postCode: String
) {
let mutableContact = contact.mutableCopy() as! CNMutableContact
mutableContact.givenName = firstName
mutableContact.familyName = lastName
if mail != "" {
let homeEmail = CNLabeledValue(label: CNLabelHome, value: mail as NSString)
mutableContact.emailAddresses = [homeEmail]
}
mutableContact.phoneNumbers = []
if phone1 != "" {
mutableContact.phoneNumbers.append(CNLabeledValue(label: CNLabelPhoneNumberMain, value: CNPhoneNumber(stringValue: phone1)))
}
let homeAddress = CNMutablePostalAddress()
homeAddress.street = street
homeAddress.city = city
homeAddress.postalCode = postCode
mutableContact.postalAddresses = [CNLabeledValue(label: CNLabelHome, value: homeAddress)]
// Save the updated created contact
let store = CNContactStore()
let saveRequest = CNSaveRequest()
saveRequest.update(mutableContact)
do {
try store.execute(saveRequest)
} catch {
print("Saving contact failed, error: \(error)")
// Handle the error.
}
}
}
My button calls this func
private func addToContacts() {
let con = ContactsClass()
if let contact = con.checkForExistingContact(familyName: klient.nachname!, givenName: klient.vorname!) {
con.updateContact(
contact: contact,
lastName: klient.nachname!,
firstName: klient.vorname!,
mail: klient.email ?? "",
phone1: klient.telefon1 ?? "",
street: selectedAddress?.strasse ?? "",
city: selectedAddress?.ort ?? "",
postCode: selectedAddress?.plz ?? ""
)
} else {
con.addToContacts(
lastName: klient.nachname!,
firstName: klient.vorname!,
mail: klient.email ?? "",
phone1: klient.telefon1 ?? "",
street: selectedAddress?.strasse ?? "",
city: selectedAddress?.ort ?? "",
postCode: selectedAddress?.plz ?? ""
)
}
}
My problem:
- Adding the contact works fine. No problems.
- Updating this contact doesn't.
Error in log:
2023-06-21 21:28:25.166437+0200 justCare 2[64058:433979] [core] Attempted to register account monitor for types client is not authorized to access: {(
"com.apple.account.CardDAV",
"com.apple.account.Exchange",
"com.apple.account.LDAP"
)}
2023-06-21 21:28:25.166546+0200 justCare 2[64058:433979] [accounts] CNAccountCollectionUpdateWatcher 0x6000020a04c0: Store registration failed: Error Domain=com.apple.accounts Code=7 "(null)"
2023-06-21 21:28:25.166605+0200 justCare 2[64058:433979] [accounts] CNAccountCollectionUpdateWatcher 0x6000020a04c0: Update event received, but store registration failed. This event will be handled, but the behavior is undefined.
2023-06-21 21:28:25.340559+0200 justCare 2[64058:433979] [api] Attempt to read notes by an unentitled app
2023-06-21 21:28:25.343112+0200 justCare 2[64058:433979] [General] A property was not requested when contact was fetched.
2023-06-21 21:28:25.348149+0200 justCare 2[64058:433979] [General] (
0 CoreFoundation 0x000000019e1d3154 _exceptionPreprocess + 176
1 libobjc.A.dylib 0x000000019dcf24d4 objc_exception_throw + 60
2 CoreFoundation 0x000000019e1d2ff8 +[NSException exceptionWithName:reason:userInfo:] + 0
3 Contacts 0x00000001b16f23c4 -[CNMutableContact setPhoneNumbers:] + 328
4 justCare 2 0x0000000100a04e04 $s10justCare_213ContactsClassC13updateContact7contact8lastName05firstI09birthDate4mail6phone16phone26mobile6street4city8postCode6gruppeySo9CNContactC_S2S10Foundation0L0VSgS8StF + 1752
5 justCare 2 0x0000000100e3eb64 $s10justCare_220KlientenAdressenViewV13addToContacts33_94E28232C5F5EF34661BF1E9CA92653DLLyyF + 6208
6 justCare 2 0x0000000100e3d314 $s10justCare_220KlientenAdressenViewV4bodyQrvg7SwiftUI05TupleE0VyAE0E0PAEE5sheet11isPresented9onDismiss7contentQrAE7BindingVySbG_yycSgqd__yctAeHRd__lFQOyAE6HStackVyAGyAE6SpacerV_AE6ButtonVyAiEE10labelStyleyQrqd__AE05LabelU0Rd__lFQOyAE0V0VyAE4TextVAE5ImageVG_AE08IconOnlyvU0VQo_GAiEE8disabledyQrSbFQOyA8__Qo_A10_SgAiEE5alert_AK7actionsQrAE18LocalizedStringKeyV_APqd__yXEtAeHRd__lFQOyA10__AGyAWyA1_G_A16_tGQo_AiEE5frame5width6height9alignmentQr12CoreGraphics7CGFloatVSg_A26_AE9AlignmentVtFQOyAE7DividerV_Qo_AiEE4helpyQrA15_FQOyA10__Qo_tGG_AA014AdresseAddEditE0VQo__AiEE0M6Change2of7performQrqd___yqd__ctSQRd__lFQOyAiEEA19_A20_A21_A22_QrA26__A26_A28_tFQOyAE4ListVyAA0cD0CAE7ForEachVyAE14FetchedResultsVyA45_G10Foundation4UUIDVSgAiEE20listRowSeparatorTint_5edgesQrAE5ColorVSg_AE12VerticalEdgeO3SetVtFQOyAiEE16listRowSeparator_A56_QrAE10VisibilityO_A63_tFQOyAiEE7paddingyQrAE4EdgeOA62_V_A26_tFQOyAiEE3tagyQrqd__SHRd__lFQOyASyAGyAiEEA19_A20_A21_A22_QrA26__A26_A28_tFQOyAE6VStackVyAGyAiEEA19_A20_A21_A22_QrA26__A26_A28_tFQOyA1__Qo_Sg_A74_A74_tGG_Qo__A73_yAGyASyAGyA1__AuiEE15foregroundColoryQrA59_FQOyA3__Qo_A80_SgA3_SgtGG_ASyAGyA1__AUA1_SgA85_tGGtGGtGG_A45_Qo__Qo__Qo__Qo_GG_Qo__AA0C0CQo_tGyXEfU_A34_yXEfU_yycfU8 + 36
7 SwiftUI 0x00000001c6e285e4 block_destroy_helper + 1276
8 SwiftUI 0x00000001c6e26978 OUTLINED_FUNCTION_1 + 23992
9 SwiftUI 0x00000001c6e269dc OUTLINED_FUNCTION_1 + 24092
10 AppKit 0x00000001a15218a8 -[NSApplication(NSResponder) sendAction:to:from:] + 440
11 AppKit 0x00000001a15216c0 -[NSControl sendAction:to:] + 72
12 AppKit 0x00000001a1521604 __26-[NSCell _sendActionFrom:]_block_invoke + 100
13 AppKit 0x00000001a152152c -[NSCell _sendActionFrom:] + 204
14 AppKit 0x00000001a1521450 -[NSButtonCell _sendActionFrom:] + 88
15 AppKit 0x00000001a151ea54 NSControlTrackMouse + 1480
16 AppKit 0x00000001a151e460 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 144
17 AppKit 0x00000001a151e318 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 488
18 AppKit 0x00000001a151d7e4 -[NSControl mouseDown:] + 448
19 AppKit 0x00000001a151c2cc -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 3476
20 AppKit 0x00000001a14a6f08 -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 364
21 AppKit 0x00000001a14a6bc8 -[NSWindow(NSEventRouting) sendEvent:] + 284
22 AppKit 0x00000001a14a5f0c -[NSApplication(NSEvent) sendEvent:] + 1556
23 AppKit 0x00000001a16f5fc4 -[NSApplication _handleEvent:] + 60
24 AppKit 0x00000001a136d368 -[NSApplication run] + 500
25 AppKit 0x00000001a1344794 NSApplicationMain + 880
26 SwiftUI 0x00000001c643f6b8 OUTLINED_FUNCTION_8 + 8272
27 SwiftUI 0x00000001c75a05ac OUTLINED_FUNCTION_14 + 188
28 SwiftUI 0x00000001c6e20c48 OUTLINED_FUNCTION_1 + 136
29 justCare 2 0x0000000101365e9c $s10justCare_20aB5_2AppV5$mainyyFZ + 40
30 justCare 2 0x000000010136619c main + 12
31 dyld 0x000000019dd23f28 start + 2236
)
Why isn't the contact updated? I would be very thankful for help.
</details>
# 答案1
**得分**: 1
错误似乎出现在根据堆栈跟踪修改联系人的电话号码部分。
>3 Contacts 0x00000001b16f23c4 -[CNMutableContact setPhoneNumbers:] + 328
还有这个消息:
>在获取联系人时未请求属性。
查看您的代码,您的 `checkForExistingContact` 方法仅获取属性 `CNContactGivenNameKey`、`CNContactFamilyNameKey` 和 `CNContactEmailAddressesKey`。电话号码键未列出。
在 [`CNMutableContact`](https://developer.apple.com/documentation/contacts/cnmutablecontact) 文档中还有这个注意事项:
>您只能修改那些从联系人数据库中检索到的属性值。在获取联系人时,您指定要从数据库中检索哪些属性。然后,联系人存储将使用这些值填充 `CNContact` 对象的属性。在创建该对象的可变副本后,您只能修改那些存在值的属性。如果尝试访问不可用的属性,则 `CNMutableContact` 对象会引发 `CNContactPropertyNotFetchedExceptionName` 异常。
您需要更新以下行:
```swift
let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactEmailAddressesKey] as [CNKeyDescriptor]
以包括您在 updateContact
方法中尝试更新的所有可能的键。
英文:
The error seems to be around modifying the contact's phone number based on the stack trace.
>3 Contacts 0x00000001b16f23c4 -[CNMutableContact setPhoneNumbers:] + 328
There's also the message:
>A property was not requested when contact was fetched.
Looking at your code, your checkForExistingContact
method only fetches the attributes CNContactGivenNameKey
, CNContactFamilyNameKey
, and CNContactEmailAddressesKey
. The phone number key is not listed.
There is also this note in the documentation for CNMutableContact
:
>You may modify only those properties whose values you fetched from the contacts database. When fetching a contact, you specify which properties you want to retrieve from the database. The contact store then populates the properties of a CNContact
object with those values. After creating a mutable copy of that object, you can modify only those properties for which a value exists. If you attempt to access a property that is not available, the CNMutableContact
object throws a CNContactPropertyNotFetchedExceptionName
exception.
You need to update the line:
let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactEmailAddressesKey] as [CNKeyDescriptor]
to include all possible keys you will try to update in your updateContact
method.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论