以编程方式请求访问联系人

自从升级到 iOS6以来,我注意到在 iPhone 地址簿中添加联系人的代码不再有效。我认为这是一个与权限相关的问题,因为苹果现在在访问联系人之前需要用户权限(解决 这个问题)。

我希望应用程序能自动请求访问联系人的权限,就像下面的截图一样,但它没有。尝试添加联系人只是失败与 ABAddressBookErrorDomain error 1

我是否需要以编程方式启动访问联系人请求对话框? 如何做到这一点?

access contacts

87198 次浏览

With iOS 6 you have to ask permission like this

requestAccessToEntityType:EKEntityTypeEvent completion:

As per this documentation on apple's site (scroll down to Privacy in the middle of the page), access to the address book must be granted before it can be access programmatically. Here is what I ended up doing.

  #import <AddressBookUI/AddressBookUI.h>


// Request authorization to Address Book
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);


if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
if (granted) {
// First time access has been granted, add the contact
[self _addContactToAddressBook];
} else {
// User denied access
// Display an alert telling user the contact could not be added
}
});
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized) {
// The user has previously given access, add the contact
[self _addContactToAddressBook];
}
else {
// The user has previously denied access
// Send an alert telling user to change privacy setting in settings app
}

Update For iOS 9 and later:

From Apple website :

Important

The Address Book UI framework is deprecated in iOS 9. Use the APIs defined in the ContactsUI framework instead. To learn more, see ContactsUI

That did the perfect trick for me!

On iOS6, apple introduce new privacy control, user can control the accessment of contact and calender by each app. So, in the code side, you need to add some way to request the permission. In iOS5 or before, we can always call

ABAddressBookRef addressBook = ABAddressBookCreate();

to get the addressbook without any problem, but in iOS6, if you don't have permission, this call will just return empty pointer. That why we need to change the method to get ABAddressBookRef.

__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}


if (accessGranted) {
// Do whatever you want here.
}

In the code,semaphore is used for blocking until response, while ABAddressBookRequestAccessWithCompletion will ask for permission if the app didn't ask before. Otherwise it will just follow the settings in Settings-Privacy-Contact.

SOURCE: http://programmerjoe.blogspot.com/2012/10/ios6-permissions-contacts.html

ABAddressBookRef addressBook = ABAddressBookCreate();


__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}


if (accessGranted) {
if(self.isContactsChanged)
{
{
self.isContactsChanged=NO;
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
ABAddressBookRegisterExternalChangeCallback(addressBook, addressBookChanged, self);


int allPeopleCount = CFArrayGetCount(allPeople);


NSMutableArray *contactArrTemp = [[NSMutableArray alloc]init];


__block int noNumberCount=1;
managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
newMoc = [[NSManagedObjectContext alloc] init];
[newMoc setPersistentStoreCoordinator:[[AppDelegate getAppDelegate] persistentStoreCoordinator]];
[self DeleteAllPhoneContact];
NSNotificationCenter *notify = [NSNotificationCenter defaultCenter];
[notify addObserver:self
selector:@selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:newMoc];
self.backgroundQueue = dispatch_queue_create("com.storephonecontacts.bgqueue", NULL);
__block NSMutableDictionary *dic;
__block NSString *strTime,*strName,*strMobile,*strEmail,*strNotes;
__block NSDate *nsDate;
dispatch_async(self.backgroundQueue, ^{


NSMutableDictionary *dict =nil;
for (int i = 0; i < allPeopleCount; i++)
{


dic = [[NSMutableDictionary alloc]init];
ABRecordRef record = CFArrayGetValueAtIndex(allPeople,i);
NSDate *date = (NSDate*)ABRecordCopyValue(record, kABPersonCreationDateProperty);
nsDate = [date retain];


NSDateFormatter *formatterTime = [[NSDateFormatter alloc] init];
[formatterTime setDateFormat:@"hh.mm"];
NSString    *dateStrPhone = [formatterTime stringFromDate:date];
strTime = [dateStrPhone retain];
[formatterTime release];


NSString *name = (NSString*)ABRecordCopyValue(record, kABPersonFirstNameProperty);
if([name length]>0)
name = [name stringByAppendingString:@" "];
NSString *name1 = (NSString*)ABRecordCopyValue(record, kABPersonLastNameProperty);
if([name1 length]>0)
{
if([name length]>0)
name = [name stringByAppendingString:name1];
else
name = (NSString*)ABRecordCopyValue(record, kABPersonLastNameProperty);
}
if([name length]>0)
strName = [name retain];
else
strName = [@"noName" retain];


//to save notes
NSString *notes = (NSString*)ABRecordCopyValue(record, kABPersonNoteProperty);
if(notes == NULL){
strNotes = @"noNotes";
}
else{
strNotes = [notes retain];
}
//for image
if (!ABPersonHasImageData(record)){


}
else{
CFDataRef imageData = ABPersonCopyImageData(record);
UIImage *image = [UIImage imageWithData:(NSData *) imageData];
[dic setObject:image forKey:@"image"];
CFRelease(imageData);
}
//To set Mobile
NSMutableArray* mobileArray = [[NSMutableArray alloc] init];
ABMutableMultiValueRef multi = ABRecordCopyValue(record, kABPersonPhoneProperty);
if (ABMultiValueGetCount(multi) > 0) {
// collect all emails in array
for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {


CFStringRef mobileRef = ABMultiValueCopyValueAtIndex(multi, i);
CFStringRef locLabel = ABMultiValueCopyLabelAtIndex(multi, i);
NSString *phoneLabel =(NSString*) ABAddressBookCopyLocalizedLabel(locLabel);


if([phoneLabel isEqualToString:@"mobile"])
[mobileArray addObject:(NSString *)mobileRef];
else if([phoneLabel isEqualToString:@"iPhone"])
[mobileArray addObject:(NSString *)mobileRef];
else if([phoneLabel isEqualToString:@"home"])
[mobileArray addObject:(NSString *)mobileRef];
else if([phoneLabel isEqualToString:@"work"])
[mobileArray addObject:(NSString *)mobileRef];
else if([phoneLabel isEqualToString:@"main"])
[mobileArray addObject:(NSString *)mobileRef];
else if([phoneLabel isEqualToString:@"other"])
[mobileArray addObject:(NSString *)mobileRef];
CFRelease(mobileRef);
CFRelease(locLabel);
}
}
CFRelease(multi);
if([mobileArray count]>0)
strMobile = [[mobileArray objectAtIndex:0]retain];
else{
NSString *str=[NSString stringWithFormat:@"noNumber%i",noNumberCount];
strMobile = [str retain];
noNumberCount++;
}
[mobileArray release];


//To set E-mail
NSMutableArray* emailArray = [[NSMutableArray alloc] init];
multi = ABRecordCopyValue(record, kABPersonEmailProperty);
if (ABMultiValueGetCount(multi) > 0) {
// collect all emails in array
for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {
CFStringRef emailRef = ABMultiValueCopyValueAtIndex(multi, i);
[emailArray addObject:(NSString *)emailRef];
CFRelease(emailRef);
}
}


CFRelease(multi);
if([emailArray count]>0)
strEmail = [[emailArray objectAtIndex:0]retain];
else
strEmail = [@"noemail" retain];
[emailArray release];


bool addBool = NO;


if([strName isEqualToString:@"noName"]){
if([strEmail isEqualToString:@"noemail"]){


}
else{
[dic setObject:strEmail forKey:@"name"];
addBool = YES;
}


if(addBool == NO){
if([strMobile isEqualToString:@"noNumber"]){


}
else{
[dic setObject:strMobile forKey:@"name"];
addBool = YES;
}
}
}
else{
[dic setObject:strName forKey:@"name"];
addBool = YES;
}
[dic setObject:strEmail forKey:@"email"];
[dic setObject:strMobile forKey:@"mobile"];
[dic setObject:nsDate forKey:@"date"];
[dic setObject:strTime forKey:@"time"];
[dic setObject:strNotes forKey:@"notes"];


if(addBool == YES)
[contactArrTemp addObject:dic];


if([strMobile hasPrefix:@"0"]){
NSString *contactNumber=[strMobile stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""];
if(contactNumber.length>7)
[dic setObject:@"iPhone" forKey:@"ContactType"];


}
else {
if(strMobile.length>9)
[dic setObject:@"iPhone" forKey:@"ContactType"];


}
if(![[dic objectForKey:@"ContactType"] isKindOfClass:[NSNull class]] && [dic objectForKey:@"ContactType"])
{
[self InsertContactWithContactInfoDictionary:dic];
}
[strName release];
[nsDate release];
[strEmail release];
[strMobile release];
[strTime release];
[strNotes release];
[dic release];
}
dispatch_async(self.backgroundQueue, ^(void){ [self gcdDidFinishaddfebriteParsing:dict]; });
dispatch_release(self.backgroundQueue);
self.backgroundQueue=nil;
});


}
}
else
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"PhoneContactsSaved" object:nil userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:@"Successful"]];
[[NSNotificationCenter defaultCenter] postNotificationName:@"updateContacts" object:nil userInfo:[NSDictionary dictionaryWithObject:@"success" forKey:@"update"]];
}
}

If anyone have problem with addressBook in iOS5 then Use

ABAddressBookRef addressBook = ABAddressBookCreate();

Insted of

ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL,NULL);

Had some problems with yunas code on iOS6.1 in Xcode5. With some small adaptions it worked for me.

The problem was that ARC in iOS 6, did not allows dispatch_release(sema); Here's the working code. Note: I use m_addressbook instead of addressbook as ABAddressBookRef!

ViewController.m

#import "ViewController.h"
#import <AddressBook/AddressBook.h>
#import <AddressBook/ABAddressBook.h>
#import <AddressBook/ABPerson.h>


@interface ViewController ()


@property (nonatomic, strong) NSMutableArray* contactList;


@end


@implementation ViewController


- (void)viewDidLoad
{
[super viewDidLoad];


ABAddressBookRef m_addressbook =  ABAddressBookCreateWithOptions(NULL, NULL);


__block BOOL accessGranted = NO;
if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@autoreleasepool {
// Write your code here...
// Fetch data from SQLite DB
}
});


ABAddressBookRequestAccessWithCompletion(m_addressbook, ^(bool granted, CFErrorRef error) {
accessGranted = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}


if (accessGranted) {
// do your stuff
}
}


// ...
- (void)viewDidLoad
{
[super viewDidLoad];




[self loadPhoneContacts];
}






-(void)loadPhoneContacts{


ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();


if (status == kABAuthorizationStatusDenied) {
// if you got here, user had previously denied/revoked permission for your
// app to access the contacts, and all you can do is handle this gracefully,
// perhaps telling the user that they have to go to settings to grant access
// to contacts


[[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
return;
}


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


if (error) {
NSLog(@"ABAddressBookCreateWithOptions error: %@", CFBridgingRelease(error));
if (addressBook) CFRelease(addressBook);
return;
}


if (status == kABAuthorizationStatusNotDetermined) {


// present the user the UI that requests permission to contacts ...


ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (error) {
NSLog(@"ABAddressBookRequestAccessWithCompletion error: %@", CFBridgingRelease(error));
}


if (granted) {
// if they gave you permission, then just carry on


[self listPeopleInAddressBook:addressBook];
} else {
// however, if they didn't give you permission, handle it gracefully, for example...


dispatch_async(dispatch_get_main_queue(), ^{
// BTW, this is not on the main thread, so dispatch UI updates back to the main queue


[[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
});
}


if (addressBook) CFRelease(addressBook);
});


} else if (status == kABAuthorizationStatusAuthorized) {
[self listPeopleInAddressBook:addressBook];
if (addressBook) CFRelease(addressBook);
}
}


- (void)listPeopleInAddressBook:(ABAddressBookRef)addressBook
{
NSInteger numberOfPeople = ABAddressBookGetPersonCount(addressBook);
NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));


for (NSInteger i = 0; i < numberOfPeople; i++) {
ABRecordRef person = (__bridge ABRecordRef)allPeople[i];


NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName  = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
NSLog(@"Name:%@ %@", firstName, lastName);


ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);


CFIndex numberOfPhoneNumbers = ABMultiValueGetCount(phoneNumbers);
for (CFIndex i = 0; i < numberOfPhoneNumbers; i++) {
NSString *phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, i));
NSLog(@"  phone:%@", phoneNumber);
}


CFRelease(phoneNumbers);


NSLog(@"=============================================");
}
}

To get Addressbook in ios

- (void)retreiveAllContacts
{
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);


CFArrayRef people = ABAddressBookCopyArrayOfAllPeople(addressBook);


if (!people) {
return ;
}


CFMutableArrayRef peopleMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault,
CFArrayGetCount(people),
people);


CFArraySortValues(peopleMutable,
CFRangeMake(0, CFArrayGetCount(peopleMutable)),
(CFComparatorFunction) ABPersonComparePeopleByName,
(void*) ABPersonGetSortOrdering());


NSMutableArray *contacts = [[NSMutableArray alloc] initWithCapacity:CFArrayGetCount(peopleMutable)];


for (CFIndex i = 0; i < CFArrayGetCount(peopleMutable); i++)
{


ABRecordRef person = CFArrayGetValueAtIndex(peopleMutable, i);


int32_t recId  =  ABRecordGetRecordID(person);


NSString * abId = [NSString stringWithFormat:@"%d", recId];


ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty);


ABMultiValueRef emailIds = ABRecordCopyValue(person, kABPersonEmailProperty);




NSString* firstName = (__bridge NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty);


NSString* lastName = (__bridge NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty);


NSString* companyName = (__bridge NSString*)ABRecordCopyValue(person, kABPersonOrganizationProperty);


NSString* displayName = [firstName ? firstName : @"" stringByAppendingFormat:@" %@", lastName ? lastName : @""];


displayName = [displayName stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" "]];




NSMutableDictionary* contactInfo = [[NSMutableDictionary alloc] init];


if(ABPersonHasImageData(person))
{
CFDataRef imageDataRef = ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail);


NSData * imageData = (__bridge NSData *)imageDataRef;


UIImage * thumbImage = [UIImage imageWithData:imageData];


[contactInfo setObject:thumbImage forKey:@"picture"];
}


if(!firstName)
firstName = @"";


if (!lastName)
lastName = @"";


if(!displayName)
displayName = @"";


if(!companyName)
companyName = @"";


// [contactInfo setObject:[firstName capitalizedString] forKey:kFirstNameKey];


//[contactInfo setObject:[lastName capitalizedString] forKey:kLastNameKey];


[contactInfo setObject:[displayName capitalizedString] forKey:@"name"];


[contactInfo setObject:abId forKey:@"ABID"];




//  [contactInfo setObject:companyName forKey:kCompanyNameKey];


NSMutableArray* phoneNumbersList = [[NSMutableArray alloc] init];


for (CFIndex j=0; j < ABMultiValueGetCount(phoneNumbers); j++)
{
NSString* phone = (__bridge NSString*)ABMultiValueCopyValueAtIndex(phoneNumbers, j);


CFStringRef localizedLabel = ABMultiValueCopyLabelAtIndex(phoneNumbers,j);


//  NSString *phoneLabel =(__bridge NSString*) ABAddressBookCopyLocalizedLabel(localizedLabel);




if( phone)
{
//                NSLog(@"validatedPhone: %@", validatedPhone);




[phoneNumbersList addObject:phone];
}


if (localizedLabel) {
//                            NSLog(@"localizedLabel: %@", localizedLabel);
CFRelease(localizedLabel);
}
}


if(phoneNumbers)
{
//                        NSLog(@"phoneNumbers: %@", phoneNumbers);


CFRelease(phoneNumbers);


//            NSLog(@"phoneNumbers Release: %@", phoneNumbers);


}


[contactInfo setObject:phoneNumbersList forKey:@"phoneNumbers"];


NSMutableArray * emailList = [[NSMutableArray alloc] init];


for (CFIndex j=0; j < ABMultiValueGetCount(emailIds); j++)
{
NSString* email = (__bridge NSString*)ABMultiValueCopyValueAtIndex(emailIds, j);


CFStringRef localizedLabel = ABMultiValueCopyLabelAtIndex(emailIds, j);




if(email)
{




[emailList addObject:email];
}


}


if(emailIds)
{
CFRelease(emailIds);


}


if(emailList && [emailList count])
[contactInfo setObject:emailList forKey:@"emails"];


if ([phoneNumbersList count] > 0 || [emailList count] > 0) {
[contacts addObject:contactInfo];
}
}


//CFRelease();
CFRelease(people);


if([contacts count])
{
[self createiOSContactsDataSourceWithFeed:contacts];
}


}
ABAddressBookRequestAccessWithCompletion(ABAddressBookCreateWithOptions(NULL, nil), ^(bool granted, CFErrorRef error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (!granted){
[[[UIAlertView alloc] initWithTitle:@"Contacts Access Denied"
message:@"This app requires access to your device's Contacts.\n\nPlease enable Contacts access for this app in Settings / Privacy / Contacts"
delegate:nil
cancelButtonTitle:@"Dismiss"
otherButtonTitles:nil] show];
} else {
//access authorized
}
});
});

For add description to alert use in InfoPlist.strings.

NSContactsUsageDescription = "TESTING!";

For contacts framework:

- (void)checkPermissionForCNContacts
{
switch ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts])
{
case CNAuthorizationStatusNotDetermined:
{
[[[CNContactStore alloc] init] requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted == YES)
[self showCNContactPicker];
}];
}
break;
case CNAuthorizationStatusRestricted:
case CNAuthorizationStatusDenied:
// Show custom alert
break;
case CNAuthorizationStatusAuthorized:
[self showCNContactPicker];
break;
}
}

Swift 3. Don't forget to import Contacts

func requestForContactAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void) {
let authorizationStatus = CNContactStore.authorizationStatus(for: CNEntityType.contacts)
switch authorizationStatus {
case .authorized:
completionHandler(true)
case .denied, .notDetermined:
self.contactStore.requestAccess(for: CNEntityType.contacts, completionHandler: { (access, accessError) -> Void in
if access {
completionHandler(access)
} else {
if authorizationStatus == CNAuthorizationStatus.denied {
DispatchQueue.main.async(execute: { () -> Void in
let message = "\(accessError!.localizedDescription)\n\nPlease allow the app to access your contacts through the Settings."
self.showMessage(message: message)
})
}
}
})
default:
completionHandler(false)
}
}

This code shows how to set the permission and how to get all the contacts from the phone and show the contacts in the list with the label tag

var contactStore = CNContactStore()
var contactArray = [CNContact]()


func getContacts()
{


if CNContactStore.authorizationStatus(for: .contacts) == .notDetermined
{


contactStore.requestAccess(for: .contacts, completionHandler: { (authorized:Bool, error:Error?) in


if authorized {






let requestForContacts = CNContactFetchRequest(keysToFetch: [CNContactFormatter.descriptorForRequiredKeys(for: CNContactFormatterStyle.fullName), CNContactPhoneNumbersKey as CNKeyDescriptor, CNContactImageDataKey as CNKeyDescriptor, CNContactNicknameKey as CNKeyDescriptor])
do{
try self.contactStore.enumerateContacts(with: requestForContacts) { (contacts : CNContact, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
self.contactArray.append(contacts)
//print("hello")
}
}
catch {
print("EXCEPTION COUGHT")
}
}
})
}
else if CNContactStore.authorizationStatus(for: .contacts) == .authorized
{
let requestForContacts = CNContactFetchRequest(keysToFetch: [CNContactFormatter.descriptorForRequiredKeys(for: CNContactFormatterStyle.fullName), CNContactPhoneNumbersKey as CNKeyDescriptor, CNContactImageDataKey as CNKeyDescriptor, CNContactNicknameKey as CNKeyDescriptor])
do{
try self.contactStore.enumerateContacts(with: requestForContacts) { (contacts : CNContact, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
self.contactArray.append(contacts)
}
}
catch {


}


}
}


override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
getContacts()


}


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
//print(contactArray)
return contactArray.count


}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


let cell = tableView.dequeueReusableCell(withIdentifier: "defaultCell")


if cell != nil{


//var dig = String()
var hmdig = [String]()


let names = contactArray[indexPath.row]
print(names)


let name1 = names.givenName+" "+names.middleName+" "+names.familyName


for number in names.phoneNumbers
{
let phoneNumber = number.value


let dig = (phoneNumber.value(forKey: "digits") as? String)!
hmdig.append(dig)


}


// Set the contact image.
if let imageData = names.imageData
{
let myImage = cell?.viewWithTag(30) as! UIImageView
myImage.image = UIImage(data: imageData)
}




//            let niknm = names.nickname


let nameLable1 = cell?.viewWithTag(10) as! UILabel
nameLable1.text = name1


let nameLable2 = cell?.viewWithTag(20) as? UILabel


nameLable2?.text = hmdig.joined(separator: ",\n")


//           let nameLable3 = cell?.viewWithTag(40) as? UILabel
//                nameLable3?.text = niknm




return cell!


}
else{


return UITableViewCell()
}
}

According to iOS recent apple development documentation, apple insists to use Contact besides AddressBook.

CNAuthorizationStatus authorizationStatus = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts];
switch (authorizationStatus) {
case CNAuthorizationStatusNotDetermined: {


break;
}
case CNAuthorizationStatusRestricted: {


break;
}
case CNAuthorizationStatusDenied:{


return;
}
break;
case CNAuthorizationStatusAuthorized: {


break;
}
}

Above objective c code helps to find weather contact access permission is granted or not.