How to retrieve address book contacts with Swift?

前端 未结 1 825
离开以前
离开以前 2021-02-02 00:15

I don\'t understand why my code doesn\'t compile with Swift.

I am trying to convert this Objective-C code:

CFErrorRef error = NULL;
ABAddressBookRef addr         


        
1条回答
  •  旧巷少年郎
    2021-02-02 00:35

    Obviously, if targeting iOS version 9 or greater, you shouldn't use the AddressBook framework at all, and instead use the Contacts framework instead.

    So,

    1. Import Contacts:

      import Contacts
      
    2. Make sure to supply a NSContactsUsageDescription in your Info.plist.

    3. Then, you can then access contacts. E.g. in Swift 3:

      let status = CNContactStore.authorizationStatus(for: .contacts)
      if status == .denied || status == .restricted {
          presentSettingsActionSheet()
          return
      }
      
      // open it
      
      let store = CNContactStore()
      store.requestAccess(for: .contacts) { granted, error in
          guard granted else {
              DispatchQueue.main.async {
                  self.presentSettingsActionSheet()
              }
              return
          }
      
          // get the contacts
      
          var contacts = [CNContact]()
          let request = CNContactFetchRequest(keysToFetch: [CNContactIdentifierKey as NSString, CNContactFormatter.descriptorForRequiredKeys(for: .fullName)])
          do {
              try store.enumerateContacts(with: request) { contact, stop in
                  contacts.append(contact)
              }
          } catch {
              print(error)
          }
      
          // do something with the contacts array (e.g. print the names)
      
          let formatter = CNContactFormatter()
          formatter.style = .fullName
          for contact in contacts {
              print(formatter.string(from: contact) ?? "???")
          }
      }
      

      Where

      func presentSettingsActionSheet() {
          let alert = UIAlertController(title: "Permission to Contacts", message: "This app needs access to contacts in order to ...", preferredStyle: .actionSheet)
          alert.addAction(UIAlertAction(title: "Go to Settings", style: .default) { _ in
              let url = URL(string: UIApplication.openSettingsURLString)!
              UIApplication.shared.open(url)
          })
          alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
          present(alert, animated: true)
      }
      

    My original answer for AddressBook framework is below.


    A couple of observations:

    • If you want to use error parameter of ABAddressBookCreateWithOptions, define it to be Unmanaged?.

    • If it fails, take a look at the error object (doing takeRetainedValue so you don't leak).

    • Make sure to takeRetainedValue of the address book, too, so you don't leak.

    • You probably shouldn't just grab the contacts, but you probably should request permission first.

    Pulling that all together you get:

    // make sure user hadn't previously denied access
    
    let status = ABAddressBookGetAuthorizationStatus()
    if status == .Denied || status == .Restricted {
        // user previously denied, so tell them to fix that in settings
        return
    }
    
    // open it
    
    var error: Unmanaged?
    guard let addressBook: ABAddressBook? = ABAddressBookCreateWithOptions(nil, &error)?.takeRetainedValue() else {
        print(error?.takeRetainedValue())
        return
    }
    
    // request permission to use it
    
    ABAddressBookRequestAccessWithCompletion(addressBook) { granted, error in
        if !granted {
            // warn the user that because they just denied permission, this functionality won't work
            // also let them know that they have to fix this in settings
            return
        }
    
        if let people = ABAddressBookCopyArrayOfAllPeople(addressBook)?.takeRetainedValue() as? NSArray {
            // now do something with the array of people
        }
    }
    

    0 讨论(0)
提交回复
热议问题