导入AddressBook和AddressBookUI框架
iOS 6之前,可以通过如下方法获得通讯录
ABAddressBookRef addressBook = ABAddressBookCreate();
不过在iOS 6之后,这个方法被废弃,可以使用下面的方法获得通讯录。
AB_EXTERN ABAddressBookRef ABAddressBookCreateWithOptions(CFDictionaryRef options, CFErrorRef* error) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_6_0);
而且在ios6之后,每个App要访问通讯录都应该得到用户的授权:
//系统定义的block
typedef void(^ ABAddressBookRequestAccessCompletionHandler
)(bool granted, CFErrorRef error);
//获取授权的方法,其中第二个参数是上面定义的block
AB_EXTERN void ABAddressBookRequestAccessWithCompletion(ABAddressBookRef addressBook, ABAddressBookRequestAccessCompletionHandler completion) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_6_0);
代码如下:
-(void)getAddress { //typedef CFTypeRef ABAddressBookRef; //typedef const void * CFTypeRef; //指向常量的指针 ABAddressBookRef addressBook = nil; //判断当前系统的版本 if ([[UIDevice currentDevice].systemVersion floatValue] >= 6.0) { //如果不小于6.0,使用对应的api获取通讯录,注意,必须先请求用户的同意,如果未获得同意或者用户未操作,此通讯录的内容为空 addressBook = ABAddressBookCreateWithOptions(NULL, NULL);//等待同意后向下执行//为了保证用户同意后在进行操作,此时使用多线程的信号量机制,创建信号量,信号量的资源数0表示没有资源,调用dispatch_semaphore_wait会立即等待。若对此处不理解,请参看GCD信号量同步相关内容。 dispatch_semaphore_t sema = dispatch_semaphore_create(0);//发出访问通讯录的请求 ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error){ //如果用户同意,才会执行此block里面的方法 //此方法发送一个信号,增加一个资源数 dispatch_semaphore_signal(sema);}); //如果之前的block没有执行,则sema的资源数为零,程序将被阻塞 //当用户选择同意,block的方法被执行, sema资源数为1; dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_release(sema); }//如果系统是6.0之前的系统,不需要获得同意,直接访问 else{ addressBook = ABAddressBookCreate(); } //通讯录信息已获得,开始取出 CFArrayRef results = ABAddressBookCopyArrayOfAllPeople(addressBook); //联系人条目数(使用long而不使用int是为了兼容64位) long peopleCount = CFArrayGetCount(results); for (int i=0; i<peopleCount; i++) { ABRecordRef record = CFArrayGetValueAtIndex(results, i); NSString *firstName,*lastName; firstName = nil; lastName= nil; CFTypeRef tmp = NULL; //firstName tmp = ABRecordCopyValue(record, kABPersonFirstNameProperty); if (tmp) { firstName = [NSString stringWithString:tmp]; CFRelease(tmp);tmp = NULL; } //lastName tmp = ABRecordCopyValue(record, kABPersonLastNameProperty); if (tmp){ lastName= [NSString stringWithString:tmp]; CFRelease(tmp); tmp = NULL; } //取得完整名字(与上面firstName、lastName无关) CFStringRef fullName=ABRecordCopyCompositeName(record); NSLog(@"%@",(NSString*)fullName); // 读取电话,不只一个 ABMultiValueRef phones = ABRecordCopyValue(record, kABPersonPhoneProperty); long phoneCount = ABMultiValueGetCount(phones); for (int j=0; j<phoneCount; j++) { // label CFStringRef lable = ABMultiValueCopyLabelAtIndex(phones, j); // phone number CFStringRef number = ABMultiValueCopyValueAtIndex(phones, j); // localize label CFStringRef local = ABAddressBookCopyLocalizedLabel(lable); //此处可使用一个自定义的model类来存储姓名和电话信息。我在这里就直接输出了。 NSLog(@"number%@" ,(NSString *)number); if (local)CFRelease(local); if (lable) CFRelease(lable); if (number)CFRelease(number); } if (phones) CFRelease(phones); record = NULL; } if (results)CFRelease(results); results = nil; if (addressBook)CFRelease(addressBook); addressBook = NULL; }
请求访问通讯录,只有第一次会弹出警示框询问用户。可通过以下方法判断状态来提醒用户
typedef CF_ENUM(CFIndex, ABAuthorizationStatus) { kABAuthorizationStatusNotDetermined = 0, kABAuthorizationStatusRestricted, kABAuthorizationStatusDenied, kABAuthorizationStatusAuthorized }; AB_EXTERN ABAuthorizationStatus ABAddressBookGetAuthorizationStatus(void) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_6_0);
//获得状态,根据状态判断
ABAuthorizationStatus statu=ABAddressBookGetAuthorizationStatus();