alionthego
alionthego

Reputation: 9773

Is it possible to fetch a CNContact with all keys?

I am trying to share a CNContact between users in my app.

At the moment I'm using a CNContactFetchRequest to fetch the contacts and the user will select one to send.

But I need to define the keys using this request. I want to share the entire contact. Is that possible? I tried omitting the keys argument in the fetch request to get all keys but it threw an error ('init()' is unavailable).

Using this fetch method below I need to recreate the contact and all the fields which is quite a bit of work. I want to serialize the CNContact object and send the data to another app but can't figure out how to do that.

let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactOrganizationNameKey, CNContactPhoneNumbersKey, CNContactEmailAddressesKey, CNContactPostalAddressesKey]
let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])
do {
    try store.enumerateContacts(with: request, usingBlock: { (contact, stopPointer) in
        self.contacts.append(Contact(firstName: contact.givenName, lastName: contact.familyName, company: contact.organizationName, phoneNumbers: contact.phoneNumbers.map { $0.value.stringValue }, emailAddresses: contact.emailAddresses.map { $0.value as String }, postalAddresses: contact.postalAddresses.map { formatter.string(from: $0.value) }
        ))
    })
} catch let error {
    print("Failed to enumerate contact", error)
}

Upvotes: 2

Views: 822

Answers (1)

Alexander Khitev
Alexander Khitev

Reputation: 6861

Yes, it's possible. I made this implementation for this goal. I created an enum with all keys.

enum CNContactKeys {
    static let keysToFetch: [CNKeyDescriptor] = {
        [CNContactIdentifierKey, CNContactTypeKey, CNContactPropertyAttribute,
         CNContactNamePrefixKey, CNContactGivenNameKey, CNContactMiddleNameKey,
         CNContactFamilyNameKey, CNContactPreviousFamilyNameKey, CNContactNameSuffixKey,
         CNContactNicknameKey, CNContactPhoneticGivenNameKey, CNContactPhoneticMiddleNameKey,
         CNContactPhoneticFamilyNameKey, CNContactJobTitleKey, CNContactDepartmentNameKey,
         CNContactOrganizationNameKey, CNContactPhoneticOrganizationNameKey, CNContactPostalAddressesKey,
         CNContactEmailAddressesKey, CNContactUrlAddressesKey, CNContactInstantMessageAddressesKey,
         CNContactPhoneNumbersKey, CNContactSocialProfilesKey, CNContactBirthdayKey, CNContactDatesKey,
         CNContactImageDataKey, CNContactThumbnailImageDataKey, CNContactImageDataAvailableKey,
         CNContactRelationsKey, CNGroupNameKey, CNGroupIdentifierKey, CNContainerNameKey,
         CNContainerTypeKey, CNInstantMessageAddressServiceKey, CNInstantMessageAddressUsernameKey,
         CNSocialProfileServiceKey, CNSocialProfileURLStringKey, CNSocialProfileUsernameKey,
         CNSocialProfileUserIdentifierKey,
         CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
         CNContactFormatter.descriptorForRequiredKeys(for: .phoneticFullName)]  as? [CNKeyDescriptor] ?? []
    }()
}

Then I used keys array in a function.

func fetchContacts(_ sortOrder: CNContactSortOrder = .userDefault) async throws -> [CNContact] {
        var contacts = [CNContact]()
        let fetchRequest = CNContactFetchRequest(keysToFetch: CNContactKeys.keysToFetch)
        fetchRequest.sortOrder = sortOrder
        do {
            try contactStore.enumerateContacts(with: fetchRequest) { contact, _ in
                contacts.append(contact)
            }
            return contacts
        } catch {
            throw error
        }
    }

Upvotes: 1

Related Questions