I am accessing all Contacts with name and phone numbers. I am getting an array of CNContact with multiple phone numbers in single CNContact, which is expected.
func fetchContacts() {
let store = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactPhoneNumbersKey as any CNKeyDescriptor
]
let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch)
var result: [CNContact] = []
do {
try store.enumerateContacts(with: fetchRequest) { contact, stop in
if contact.phoneNumbers.count > 0 {
result.append(contact)
}
}
print(result)
} catch let error {
print("Fetching contacts failed: (error)")
}
}
Output:
[
Contact(fullName : "John Appleseed", phoneNumbers: ["888-555-5512", "888-555-1212"]),
Contact(fullName : "Kate Bell", phoneNumbers: ["(555) 564-8583", "(415) 555-3695"])
]
But what I want to achieve is an array of CNContact with single phone number.
[
Contact(fullName : "John Appleseed", phoneNumber: "888-555-5512"),
Contact(fullName : "John Appleseed", phoneNumber: "888-555-1212"),
Contact(fullName : "Kate Bell", phoneNumber: "(555) 564-8583"),
Contact(fullName : "Kate Bell", phoneNumber: "(415) 555-3695")
]
What NSPredictionNSPredicate
will work in this case?
NOTE: Ignore UI error, already implemented permissions, want to achieve before reading contacts (fetch request) not after reading contacts.
2
Answers
You can’t use NSPredicate to change the output of the query, it’s only meant for filtering the data. If you want a custom format for your output you are going to need a custom type
For instance
And then convert to that type in your loop
Predicates are for filtering the fetched
CNContact
objects, to limit the results to those that match some criteria. For example, you might use a predicate to fetch only contacts with phone numbers:But it won’t “split” a single
CNContact
into multiple entries, one for each phone number. You have to do that yourself. You can use the pattern that Joakim outlined (+1). Or, personally, I might use aflatMap
method that takes an array of return values and builds an array from that:That’s both a
flatMap
(for your use-case where you may want to return multiple objects for a givenCNContact
), as well as a more traditionalmap
rendition (not used here, but is my typical use-case).Anyway, you can then use it like so:
That returned: