如何使用Swift检索地址簿联系人?
我不明白为什么我的代码不能用Swift编译。
I don't understand why my code doesn't compile with Swift.
我试图转换这个Objective-C代码:
I am trying to convert this Objective-C code:
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (addressBook != nil) {
NSLog(@"Succesful.");
NSArray *allContacts = (__bridge_transfer NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
}
这是我目前在Swift中的表现:
This is my current rendition in Swift:
var error:CFErrorRef
var addressBook = ABAddressBookCreateWithOptions(nil, nil);
if (addressBook != nil) {
println("Succesful.");
var allContacts:CFArrayRef = ABAddressBookCopyArrayOfAllPeople(addressBook);
}
但是,Xcode报告:
but, Xcode reports:
'Unmanaged'不能转换为'CFArrayRef'
'Unmanaged' is not convertible to 'CFArrayRef'
你们有个主意吗? ?
显然,如果定位到iOS 9或更高版本,则不应使用 AddressBook
框架,而不是使用 Contacts
框架。
Obviously, if targeting iOS version 9 or greater, you shouldn't use the AddressBook
framework at all, and instead use the Contacts
framework instead.
所以,> p>
So,
-
导入
联系人
:
import Contacts
确保在 Info.plist
中提供 NSContactsUsageDescription
。
然后,您可以访问联系人。例如。在Swift 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) ?? "???")
}
}
其中
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)
}
我对AddressBook框架的原始答案如下。
My original answer for AddressBook framework is below.
一些观察结果:
-
如果你想使用
错误
参数ABAddressBookCreateWithOptions
,将其定义为Unmanaged< CFError>?
。
如果它失败了,看看错误对象(做 takeRetainedValue
所以你不要泄漏)。
If it fails, take a look at the error object (doing takeRetainedValue
so you don't leak).
确保地址簿的 takeRetainedValue
,所以你不要泄密。
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<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
}
}