简单的iOS通讯录操作封装(添加联系人、检查号码是否存在)
SJABHelper.h
#import <Foundation/Foundation.h> enum { ABHelperCanNotConncetToAddressBook, /**< 连接通讯录失败(iOS6之后访问通讯录需要用户许可) */ ABHelperExistSpecificContact, /**< 号码已存在 */ ABHelperNotExistSpecificContact /**< 号码不存在 */ }; typedef NSUInteger ABHelperCheckExistResultType; @interface SJABHelper : NSObject /** * 添加联系人 * * @param name 联系人姓名 * @param num 电话号码 * @param label 电话号码的标签备注 * * @return 是否添加成功 */ + (BOOL)addContactName:(NSString*)name phoneNum:(NSString*)num withLabel:(NSString*)label; /** * 查询指定号码是否已存在于通讯录中 * * @param phoneNum 电话号码 * * @return 返回查询结果,详见枚举类型注释 */ + (ABHelperCheckExistResultType)existPhone:(NSString*)phoneNum; @end
SJABHelper.m
需要引入 AddressBook framework。
#import "SJABHelper.h" #import <AddressBook/AddressBook.h> @implementation SJABHelper + (SJABHelper*)shareControl { static SJABHelper *instance; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[SJABHelper alloc] init]; }); return instance; } - (id)init { self = [super init]; if (self) { } return self; } + (BOOL)addContactName:(NSString *)name phoneNum:(NSString *)num withLabel:(NSString *)label { return [[SJABHelper shareControl] addContactName:name phoneNum:num withLabel:label]; } - (BOOL)addContactName:(NSString*)name phoneNum:(NSString*)num withLabel:(NSString*)label { ABRecordRef record = ABPersonCreate(); CFErrorRef error; // 使用 __bridge_retained 关键字将 NSString 转换为 CFString 类型并将内存管理权从 ARC 移交出来 CFStringRef cf_name = (__bridge_retained CFTypeRef)name; CFStringRef cf_num = (__bridge_retained CFTypeRef)num; CFStringRef cf_label = (__bridge_retained CFTypeRef)label; ABRecordSetValue(record, kABPersonFirstNameProperty, cf_name, &error); ABMutableMultiValueRef multi = ABMultiValueCreateMutable(kABPersonPhoneProperty); ABMultiValueAddValueAndLabel(multi, cf_num, cf_label, NULL); ABRecordSetValue(record, kABPersonPhoneProperty, multi, &error); CFRelease(multi); ABAddressBookRef addressBook = nil; if ([[UIDevice currentDevice].systemVersion floatValue] >= 6.0) { addressBook = ABAddressBookCreateWithOptions(NULL, NULL); //等待同意后向下执行 dispatch_semaphore_t sema = dispatch_semaphore_create(0); ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { dispatch_semaphore_signal(sema); }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_release(sema); } else { addressBook = ABAddressBookCreate(); } BOOL success = ABAddressBookAddRecord(addressBook, record, &error); if (!success) { CFRelease(record); CFRelease(addressBook); return NO; }else{ success = ABAddressBookSave(addressBook, &error); CFRelease(record); CFRelease(addressBook); return success ? YES : NO; } } + (ABHelperCheckExistResultType)existPhone:(NSString *)phoneNum { return [[SJABHelper shareControl] existPhone:phoneNum]; } - (ABHelperCheckExistResultType)existPhone:(NSString*)phoneNum { ABAddressBookRef addressBook = nil; if ([[UIDevice currentDevice].systemVersion floatValue] >= 6.0) { addressBook = ABAddressBookCreateWithOptions(NULL, NULL); //等待同意后向下执行 dispatch_semaphore_t sema = dispatch_semaphore_create(0); ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { dispatch_semaphore_signal(sema); }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_release(sema); } else { addressBook = ABAddressBookCreate(); } CFArrayRef records; if (addressBook) { records = ABAddressBookCopyArrayOfAllPeople(addressBook); }else{ #ifdef DEBUG NSLog(@"can not connect to address book"); #endif return ABHelperCanNotConncetToAddressBook; } for (int i=0; i<CFArrayGetCount(records); i++) { ABRecordRef record = CFArrayGetValueAtIndex(records, i); CFTypeRef items = ABRecordCopyValue(record, kABPersonPhoneProperty); CFArrayRef phoneNums = ABMultiValueCopyArrayOfAllValues(items); if (phoneNums) { for (int j=0; j<CFArrayGetCount(phoneNums); j++) { CFStringRef cf_phone = CFArrayGetValueAtIndex(phoneNums, j); NSString *phone = (__bridge NSString *)cf_phone; if ([phoneNum isEqualToString:phone]) { CFRelease(phoneNums); CFRelease(items); CFRelease(records); CFRelease(addressBook); return ABHelperExistSpecificContact; } } CFRelease(phoneNums); } CFRelease(items); } CFRelease(records); CFRelease(addressBook); return ABHelperNotExistSpecificContact; } @end
需要注意的就是iOS6中新的用户隐私保护使得调用 ABAddressBookCreate() 时会弹出alert让用户确认是否允许,需要加上代码:
// 如果为iOS6以上系统,需要等待用户确认是否允许访问通讯录。 if ([[UIDevice currentDevice].systemVersion floatValue] >= 6.0) { addressBook = ABAddressBookCreateWithOptions(NULL, NULL); //等待同意后向下执行 dispatch_semaphore_t sema = dispatch_semaphore_create(0); ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { dispatch_semaphore_signal(sema); }); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_release(sema); }
不然addressBook在用户确认操作前是NULL,调用会导致程序crash。