Chris Mikkelsen
Chris Mikkelsen

Reputation: 4067

App freezes when requesting access to addressbook

func getContacts() {
    let store = CNContactStore()

    if CNContactStore.authorizationStatus(for: .contacts) == .notDetermined {
        store.requestAccess(for: .contacts, completionHandler: { (authorized: Bool, error: NSError?) -> Void in
            if authorized {
                self.retrieveContactsWithStore(store: store)
            }
        } as! (Bool, Error?) -> Void)
    } else if CNContactStore.authorizationStatus(for: .contacts) == .authorized {
        self.retrieveContactsWithStore(store: store)
    }
}

func retrieveContactsWithStore(store: CNContactStore) {
    do {
        let groups = try store.groups(matching: nil)
        let predicate = CNContact.predicateForContactsInGroup(withIdentifier: groups[0].identifier)
        //let predicate = CNContact.predicateForContactsMatchingName("John")
        let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactEmailAddressesKey] as [Any]

        let contacts = try store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch as! [CNKeyDescriptor])
        self.objects = contacts
        DispatchQueue.main.async(execute: { () -> Void in
            self.myTableView.reloadData()
        })
    } catch {
        print(error)
    }
}

I was trying to retrieve contacts from address book, but whenever I go to the view calling getContacts(), the app freezes. It wouldn't proceed anymore, but it didn't crash either. I wonder what went wrong here?

Upvotes: 0

Views: 263

Answers (1)

rmaddy
rmaddy

Reputation: 318774

Your code for the call to requestAccess isn't correct. The syntax for the completion handler isn't valid. You need this:

func getContacts() {
    let store = CNContactStore()

    let status = CNContactStore.authorizationStatus(for: .contacts)
    if status == .notDetermined {
        store.requestAccess(for: .contacts, completionHandler: { (authorized: Bool, error: Error?) in
            if authorized {
                self.retrieveContactsWithStore(store: store)
            }
        })
    } else if status == .authorized {
        self.retrieveContactsWithStore(store: store)
    }
}

Also note the change to use the status variable. This is cleaner and easier to read than calling authorizationStatus over and over. Call it once and then check the value over and over as needed.

Upvotes: 1

Related Questions