Search code examples
iosswiftcontactscncontactstore

How to fetch contacts NOT named "John" with Swift 3


Is there a way I can fetch contacts using the Contacts framework without an attribute?

Example:

myContactArray = unifiedContactsNotCalled("John")

PS: I know that line is nothing like the real code, it's just a serving suggestion for illustrative purposes 😉


Solution

  • Before I outline how to find those that don't match a name, let's recap how one finds those that do. In short, you'd use a predicate:

    let predicate = CNContact.predicateForContacts(matchingName: searchString)
    let matches = try store.unifiedContacts(matching: predicate, keysToFetch: [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)])    // use whatever keys you want
    

    (Obviously, you'd wrap that in a do-try-catch construct, or whatever error handling pattern you want.)

    Unfortunately, you cannot use your own custom predicates with the Contacts framework, but rather can only use the CNContact predefined predicates. Thus, if you want to find contacts whose name does not contain "John", you have to manually enumerateContacts(with:) and build your results from that:

    let formatter = CNContactFormatter()
    formatter.style = .fullName
    
    let request = CNContactFetchRequest(keysToFetch: [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)])   // include whatever other keys you may need
    
    // find those contacts that do not contain the search string
    
    var matches = [CNContact]()
    try store.enumerateContacts(with: request) { contact, stop in
        if !(formatter.string(from: contact)?.localizedCaseInsensitiveContains(searchString) ?? false) {
            matches.append(contact)
        }
    }