如何使用Swift检索地址簿联系人?

use*_*810 13 contacts addressbook swift ios8

我不明白为什么我的代码不能用Swift编译.

我试图转换这个Objective-C代码:

CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);

  if (addressBook != nil) { 
    NSLog(@"Succesful."); 

    NSArray *allContacts = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
}
Run Code Online (Sandbox Code Playgroud)

这是我目前在Swift中的演绎:

var error:CFErrorRef
var addressBook = ABAddressBookCreateWithOptions(nil, nil);

if (addressBook != nil) {
    println("Succesful.");

    var allContacts:CFArrayRef = ABAddressBookCopyArrayOfAllPeople(addressBook);
}
Run Code Online (Sandbox Code Playgroud)

但是,Xcode报道:

'Unmanaged'不能转换为'CFArrayRef'

你们有个主意吗?

Rob*_*Rob 30

显然,如果针对iOS 9或更高版本,您根本不应该使用AddressBook框架,而是使用Contacts框架.

所以,

  1. 进口Contacts:

    import Contacts
    
    Run Code Online (Sandbox Code Playgroud)
  2. 一定要提供NSContactsUsageDescription你的Info.plist.

  3. 然后,您可以访问联系人.例如在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) ?? "???")
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    哪里

    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: UIApplicationOpenSettingsURLString)!
            UIApplication.shared.open(url)
        })
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        present(alert, animated: true)
    }
    
    Run Code Online (Sandbox Code Playgroud)

我对AddressBook框架的原始答案如下.


几点意见:

  • 如果要使用error参数ABAddressBookCreateWithOptions,请将其定义为Unmanaged<CFError>?.

  • 如果失败,请查看错误对象(这样takeRetainedValue做不会泄漏).

  • 确保takeRetainedValue通讯录也是如此,这样你就不会泄漏.

  • 你可能不应该只是抓住联系人,但你可能应该首先请求许可.

拉出所有这些你得到:

// 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<CFError>?
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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 非托管&lt;CFError&gt;?是一个很好的提示。也谢谢剩下的。 (2认同)