大部分的地址簿框架在iOS 9中已经被弃用。在新的联系人框架文档中,只展示了如何匹配NSPredicate
的记录,但如果我想要所有记录呢?
Swift 5
版本:lazy var contacts: [CNContact] = {
let contactStore = CNContactStore()
let keysToFetch: [CNKeyDescriptor] = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactPostalAddressesKey as CNKeyDescriptor,
CNContactEmailAddressesKey as CNKeyDescriptor,
CNContactPhoneNumbersKey as CNKeyDescriptor,
CNContactImageDataAvailableKey as CNKeyDescriptor,
CNContactThumbnailImageDataKey as CNKeyDescriptor]
// Get all the containers
var allContainers: [CNContainer] = []
do {
allContainers = try contactStore.containers(matching: nil)
} catch {
print("Error fetching containers")
}
var results: [CNContact] = []
// Iterate all containers and append their contacts to our results array
for container in allContainers {
let fetchPredicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)
do {
let containerResults = try contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch)
results.append(contentsOf: containerResults)
} catch {
print("Error fetching results for container")
}
}
return results
}()
原始回答:
这是 Swift 3.0
版本的 flohei 的回答
lazy var contacts: [CNContact] = {
let contactStore = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactPostalAddressesKey,
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey,
CNContactImageDataAvailableKey,
CNContactThumbnailImageDataKey] as [Any]
// Get all the containers
var allContainers: [CNContainer] = []
do {
allContainers = try contactStore.containers(matching: nil)
} catch {
print("Error fetching containers")
}
var results: [CNContact] = []
// Iterate all containers and append their contacts to our results array
for container in allContainers {
let fetchPredicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)
do {
let containerResults = try contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch as! [CNKeyDescriptor])
results.append(contentsOf: containerResults)
} catch {
print("Error fetching results for container")
}
}
return results
}()
SWIFT 2
iOS9中使用Contacts Framework获取联系人的完整名称、电子邮件地址、电话号码和个人头像
注意:已处理没有姓名的联系人。
步骤1
import Contacts
步骤 2
func fetchContacts(completion: (result: NSMutableArray) -> Void )
{
let finalArrayForContacts = NSMutableArray()
let contactsArray = NSMutableArray()
let requestForContacts = CNContactFetchRequest(keysToFetch: [CNContactIdentifierKey, CNContactFormatter.descriptorForRequiredKeysForStyle(CNContactFormatterStyle.FullName), CNContactPhoneNumbersKey ,CNContactThumbnailImageDataKey])
do{
try contactStore.enumerateContactsWithFetchRequest(requestForContacts) { (contactStore : CNContact, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
contactsArray.addObject(contactStore)
}
}
catch {
}
if contactsArray.count > 0 {
let formatter = CNContactFormatter()
for contactTemp in contactsArray
{
let contactNew = contactTemp as! CNContact
//Contact Name
var stringFromContact = formatter.stringFromContact(contactNew)
if stringFromContact == nil {
stringFromContact = "Unnamed"
}
var imageData = NSData?()
if contactNew.thumbnailImageData != nil{
imageData = contactNew.thumbnailImageData!
}else{
// imageData = nil
}
var tempArray : NSArray = NSArray()
if (contactNew.phoneNumbers).count > 0 {
tempArray = ((contactNew.phoneNumbers as? NSArray)?.valueForKey("value").valueForKey("digits")) as! NSArray
for i in 0 ..< tempArray.count
{
let newDict = NSMutableDictionary()
let phoneNumber : String = (tempArray.objectAtIndex(i)) as! String
if phoneNumber.characters.count > 0 {
var test = false
if phoneNumber.hasPrefix("+")
{
test = true
}
var resultString : String = (phoneNumber.componentsSeparatedByCharactersInSet(characterSet) as NSArray).componentsJoinedByString("")
if test == true
{
resultString = "+\(resultString)"
}
newDict.setValue(resultString, forKey: "contact_phone")
newDict.setValue(stringFromContact, forKey: "contact_name")
newDict.setValue("0", forKey: "contact_select")
newDict.setValue(imageData, forKey: "contact_image")
finalArrayForContacts.addObject(newDict)
}
}
}else{
// no number saved
}
}
}else {
print("No Contacts Found")
}
completion(result: finalArrayForContacts)
}
我正在尝试这段代码,它可以正常工作。使用最新的Swift3框架和联系人,我可以使用此代码获取所有联系人详细信息:
let requestForContacts = CNContactFetchRequest(keysToFetch: [CNContactIdentifierKey as CNKeyDescriptor, CNContactFormatter.descriptorForRequiredKeys(for: CNContactFormatterStyle.fullName), CNContactPhoneNumbersKey as CNKeyDescriptor ,CNContactImageDataKey as CNKeyDescriptor,CNContactEmailAddressesKey as CNKeyDescriptor,CNContactBirthdayKey as CNKeyDescriptor])
do {
try self.store.enumerateContacts(with: requestForContacts) { contact, stop in
print("contact:\(contact)")
self.contacts.append(contact)
}
} catch {
print(error)
}
for contact in self.contacts {
print(contact)
let firstName = contact.givenName
nameArray.append(firstName)
print("first:\(firstName)")
let phoneNumber = (contact.phoneNumbers[0].value).value(forKey: "digits")
phoneNumberArray.append(phoneNumber as! String)
let emailAddress = contact.emailAddresses[0].value(forKey: "value")
emailAddressArray.append(emailAddress as! String)
}
Cody在Swift 3中的回复:
import Contacts
let store = CNContactStore()
store.requestAccess(for: .contacts, completionHandler: {
granted, error in
guard granted else {
let alert = UIAlertController(title: "Can't access contact", message: "Please go to Settings -> MyApp to enable contact permission", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
return
}
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactPhoneNumbersKey] as [Any]
let request = CNContactFetchRequest(keysToFetch: keysToFetch as! [CNKeyDescriptor])
var cnContacts = [CNContact]()
do {
try store.enumerateContacts(with: request){
(contact, cursor) -> Void in
cnContacts.append(contact)
}
} catch let error {
NSLog("Fetch contact error: \(error)")
}
print(">>>> Contact list:")
for contact in cnContacts {
let fullName = CNContactFormatter.string(from: contact, style: .fullName) ?? "No Name"
print("\(fullName): \(contact.phoneNumbers.description)")
}
})
只是想分享这个版本的 Swift 4
info.plist:
<key>NSContactsUsageDescription</key>
<string>$(PRODUCT_NAME) requires to access your contacts ...</string>
module:
import Contacts
code:
func fetchContacts(completion: @escaping (_ result: [CNContact]) -> Void){
DispatchQueue.main.async {
var results = [CNContact]()
let keys = [CNContactGivenNameKey,CNContactFamilyNameKey,CNContactMiddleNameKey,CNContactEmailAddressesKey,CNContactPhoneNumbersKey] as [CNKeyDescriptor]
let fetchRequest = CNContactFetchRequest(keysToFetch: keys)
fetchRequest.sortOrder = .userDefault
let store = CNContactStore()
store.requestAccess(for: .contacts, completionHandler: {(grant,error) in
if grant{
do {
try store.enumerateContacts(with: fetchRequest, usingBlock: { (contact, stop) -> Void in
results.append(contact)
})
}
catch let error {
print(error.localizedDescription)
}
completion(results)
}else{
print("Error \(error?.localizedDescription ?? "")")
}
})
}
}
Usage:
fetchContacts(completion: {contacts in
contacts.forEach({print("Name: \($0.givenName), number: \($0.phoneNumbers.first?.value.stringValue ?? "nil")")})
DispatchQueue.main.async
是什么意思?获取和填充结果的处理仍在主线程上进行。因此,即使 DispatchQueue.main.async
是异步调用,其中添加的重型操作也可能会冻结用户界面,因为其操作在主线程上序列执行。我认为,应该使用类似于 DispatchQueue.global(qos: .default).async { //fetch here}
这样的写法,然后在完成返回时,获取主线程并填充您的 UI。 - Rajan Maheshwari现在在iOS9中,ABAddressBookRef已经被弃用,因此要从手机中获取所有联系人,请使用这个框架并添加此函数,您将获得联系人数组。
像这样在.h类中导入联系人框架
#import <Contacts/Contacts.h>
然后在 .m 文件中添加此方法
-(void)contactsFromAddressBook{
//ios 9+
CNContactStore *store = [[CNContactStore alloc] init];
[store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted == YES) {
//keys with fetching properties
NSArray *keys = @[CNContactFamilyNameKey, CNContactGivenNameKey, CNContactPhoneNumbersKey, CNContactImageDataKey];
NSString *containerId = store.defaultContainerIdentifier;
NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:containerId];
NSError *error;
NSArray *cnContacts = [store unifiedContactsMatchingPredicate:predicate keysToFetch:keys error:&error];
if (error) {
NSLog(@"error fetching contacts %@", error);
} else {
NSString *phone;
NSString *fullName;
NSString *firstName;
NSString *lastName;
UIImage *profileImage;
NSMutableArray *contactNumbersArray;
for (CNContact *contact in cnContacts) {
// copy data to my custom Contacts class.
firstName = contact.givenName;
lastName = contact.familyName;
if (lastName == nil) {
fullName=[NSString stringWithFormat:@"%@",firstName];
}else if (firstName == nil){
fullName=[NSString stringWithFormat:@"%@",lastName];
}
else{
fullName=[NSString stringWithFormat:@"%@ %@",firstName,lastName];
}
UIImage *image = [UIImage imageWithData:contact.imageData];
if (image != nil) {
profileImage = image;
}else{
profileImage = [UIImage imageNamed:@"person-icon.png"];
}
for (CNLabeledValue *label in contact.phoneNumbers) {
phone = [label.value stringValue];
if ([phone length] > 0) {
[contactNumbersArray addObject:phone];
}
}
NSDictionary* personDict = [[NSDictionary alloc] initWithObjectsAndKeys: fullName,@"fullName",profileImage,@"userImage",phone,@"PhoneNumbers", nil];
[MutableArray__Contact addObject:personDict];
}
dispatch_async(dispatch_get_main_queue(), ^
{
NSLog(@"%@",ar_Contact);
//[self.tableViewRef reloadData];
});
}
}
}];
}
要使用此方法,请调用contactsFromAddressBook函数
[self contactsFromAddressBook];
联系人权限 iOS 9 SWIFT 2
let status : CNAuthorizationStatus = CNContactStore.authorizationStatusForEntityType(CNEntityType.Contacts)
if status == CNAuthorizationStatus.NotDetermined{
contactStore.requestAccessForEntityType(CNEntityType.Contacts, completionHandler: { (temp: Bool, error : NSError?) -> Void in
//call contacts fetching function
})
}else if status == CNAuthorizationStatus.Authorized {
//call contacts fetching function
})
}
else if status == CNAuthorizationStatus.Denied {
}
}
Swift 4.2 . 获取带有图像的联系人号码
info.plist file data
<key>NSContactsUsageDescription</key>
<string>$(PRODUCT_NAME) requires to access your contacts ...</string>
//MARK:- Fetch All Contacts of Phone
func fetchContacts(completion: @escaping (_ result: [CNContact]) -> Void){
DispatchQueue.main.async {
var results = [CNContact]()
let keys = [CNContactGivenNameKey,CNContactFamilyNameKey,CNContactMiddleNameKey,CNContactEmailAddressesKey,CNContactPhoneNumbersKey,CNContactThumbnailImageDataKey] as [CNKeyDescriptor]
let fetchRequest = CNContactFetchRequest(keysToFetch: keys)
fetchRequest.sortOrder = .userDefault
let store = CNContactStore()
store.requestAccess(for: .contacts, completionHandler: {(grant,error) in
if grant{
do {
try store.enumerateContacts(with: fetchRequest, usingBlock: { (contact, stop) -> Void in
results.append(contact)
})
}
catch let error {
print(error.localizedDescription)
}
completion(results)
}else{
print("Error \(error?.localizedDescription ?? "")")
}
})
}
}
}
在DidLoad方法中调用函数var arrpic = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
fetchContacts(completion: {contacts in
contacts.forEach({print("Name: \($0.givenName), number: \($0.phoneNumbers.first?.value.stringValue ?? "nil")")
self.arrfname.append("\($0.givenName)")
self.arrlname.append("\($0.familyName)")
self.arrnumber.append("\($0.phoneNumbers.first?.value.stringValue ?? "nil")")
var img = UIImage()
if $0.thumbnailImageData != nil
{
img = UIImage.init(data: $0.thumbnailImageData!)!
self.arrpic.add(img)
}
else
{
self.arrpic.add("")
}
})
if contacts.count > 0
{
self.tablev.reloadData()
}
})
}
@flohei 在 Swift-4
中的答案
var contacts: [CNContact] = {
let contactStore = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeys(for: CNContactFormatterStyle.fullName),
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey,
CNContactImageDataAvailableKey,
CNContactThumbnailImageDataKey] as [Any]
// Get all the containers
var allContainers: [CNContainer] = []
do {
allContainers = try contactStore.containers(matching: nil)
} catch {
print("Error fetching containers")
}
var results: [CNContact] = []
// Iterate all containers and append their contacts to our results array
for container in allContainers {
let fetchPredicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)
do {
let containerResults = try contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch as! [CNKeyDescriptor])
results.append(contentsOf: containerResults)
} catch {
print("Error fetching results for container")
}
}
return results
}()
如果您想通过已知标识符获取联系人的所有字段:
let contact = unifiedContact(withIdentifier: identifier, keysToFetch: [CNContactVCardSerialization.descriptorForRequiredKeys()])
这将使您访问所有字段,例如地址、电话号码、全名等。
要检索fullName,则:
let fullname = CNContactFormatter.string(from: contact, style: .fullName)