IOS獲取系統通訊錄聯絡人資訊
IOS關於通訊錄的開發有兩種,一種是直接呼叫系統的通訊錄介面,根據回撥資訊處理資料,另一種是直接獲取系統的通訊錄,完全自定義UI,並且可以通過官方給我們提供的介面進行讀寫。這篇部落格主要討論第二種方式。
一、許可權註冊
隨著apple對使用者隱私的越來越重視,IOS系統的許可權設定也更加嚴格,在獲取系統通訊錄之前,我們必須獲得使用者的授權。許可權申請程式碼示例如下:
//這個變數用於記錄授權是否成功,即使用者是否允許我們訪問通訊錄
int
__block tip=0;
//宣告一個通訊簿的引用
ABAddressBookRef addBook =nil;
//因為在IOS6.0之後和之前的許可權申請方式有所差別,這裡做個判斷
if
([[UIDevice currentDevice].systemVersion floatValue]>=6.0) {
//建立通訊簿的引用
addBook=ABAddressBookCreateWithOptions(NULL, NULL);
//建立一個出事訊號量為0的訊號
dispatch_semaphore_t sema=dispatch_semaphore_create(0);
//申請訪問許可權
ABAddressBookRequestAccessWithCompletion(addBook, ^(
bool
greanted, CFErrorRef error) {
//greanted為YES是表示使用者允許,否則為不允許
if
(!greanted) {
tip=1;
}
//傳送一次訊號
dispatch_semaphore_signal(sema);
});
//等待訊號觸發
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}
else
{
//IOS6之前
addBook =ABAddressBookCreate();
}
if
(tip) {
//做一個友好的提示
UIAlertView * alart = [[UIAlertView alloc]initWithTitle:@
"溫馨提示"
message:@
"請您設定允許APP訪問您的通訊錄\nSettings>General>Privacy"
delegate:self cancelButtonTitle:@
"確定"
otherButtonTitles:nil, nil];
[alart show];
return
;
}
幾點注意:1、dispatch_semaphore_t三個相關的操作為
dispatch_semaphore_create 建立一個訊號
dispatch_semaphore_signal 傳送一個訊號
dispatch_semaphore_wait 等待訊號觸發
dispatch_semaphore_create()建立一個訊號,後面可以跟一個引數,表示訊號量,當訊號量正值時,dispatch_semaphore_wait後面的程式碼會被執行,否則程式將會一直等待在dispatch_semaphore_wait。 dispatch_semaphore_signal的作用是傳送一個訊號,會使訊號量加1,相對的,dispatch_semaphore_wait執行後會使訊號量減1.
2、因為是否被授權是在ABAddressBookRequestAccessWithCompletion的block回撥中獲取的,所以我們需要在外面做一個執行緒等待。
二、獲取通訊錄聯絡人詳細資訊
//獲取所有聯絡人的陣列
CFArrayRef allLinkPeople = ABAddressBookCopyArrayOfAllPeople(addBook);
//獲取聯絡人總數
CFIndex number = ABAddressBookGetPersonCount(addBook);
//進行遍歷
for
(NSInteger i=0; i<number; i++) {
//獲取聯絡人物件的引用
ABRecordRef people = CFArrayGetValueAtIndex(allLinkPeople, i);
//獲取當前聯絡人名字
NSString*firstName=(__bridge NSString *)(ABRecordCopyValue(people, kABPersonFirstNameProperty));
//獲取當前聯絡人姓氏
NSString*lastName=(__bridge NSString *)(ABRecordCopyValue(people, kABPersonLastNameProperty));
//獲取當前聯絡人中間名
NSString*middleName=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonMiddleNameProperty));
//獲取當前聯絡人的名字字首
NSString*prefix=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonPrefixProperty));
//獲取當前聯絡人的名字字尾
NSString*suffix=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonSuffixProperty));
//獲取當前聯絡人的暱稱
NSString*nickName=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonNicknameProperty));
//獲取當前聯絡人的名字拼音
NSString*firstNamePhoneic=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonFirstNamePhoneticProperty));
//獲取當前聯絡人的姓氏拼音
NSString*lastNamePhoneic=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonLastNamePhoneticProperty));
//獲取當前聯絡人的中間名拼音
NSString*middleNamePhoneic=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonMiddleNamePhoneticProperty));
//獲取當前聯絡人的公司
NSString*organization=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonOrganizationProperty));
//獲取當前聯絡人的職位
NSString*job=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonJobTitleProperty));
//獲取當前聯絡人的部門
NSString*department=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonDepartmentProperty));
//獲取當前聯絡人的生日
NSString*birthday=(__bridge NSDate*)(ABRecordCopyValue(people, kABPersonBirthdayProperty));
NSMutableArray * emailArr = [[NSMutableArray alloc]init];
//獲取當前聯絡人的郵箱 注意是陣列
ABMultiValueRef emails= ABRecordCopyValue(people, kABPersonEmailProperty);
for
(NSInteger j=0; j<ABMultiValueGetCount(emails); j++) {
[emailArr addObject:(__bridge NSString *)(ABMultiValueCopyValueAtIndex(emails, j))];
}
//獲取當前聯絡人的備註
NSString*notes=(__bridge NSString*)(ABRecordCopyValue(people, kABPersonNoteProperty));
//獲取當前聯絡人的電話 陣列
NSMutableArray * phoneArr = [[NSMutableArray alloc]init];
ABMultiValueRef phones= ABRecordCopyValue(people, kABPersonPhoneProperty);
for
(NSInteger j=0; j<ABMultiValueGetCount(phones); j++) {
[phonerr addObject:(__bridge NSString *)(ABMultiValueCopyValueAtIndex(phones, j))];
}
//獲取建立當前聯絡人的時間 注意是NSDate
NSDate*creatTime=(__bridge NSDate*)(ABRecordCopyValue(people, kABPersonCreationDateProperty));
//獲取最近修改當前聯絡人的時間
NSDate*alterTime=(__bridge NSDate*)(ABRecordCopyValue(people, kABPersonModificationDateProperty));
//獲取地址
ABMultiValueRef address = ABRecordCopyValue(people, kABPersonAddressProperty);
for
(
int
j=0; j<ABMultiValueGetCount(address); j++) {
//地址型別
NSString * type = (__bridge NSString *)(ABMultiValueCopyLabelAtIndex(address, j));
NSDictionary * temDic = (__bridge NSDictionary *)(ABMultiValueCopyValueAtIndex(address, j));
//地址字串,可以按需求格式化
NSString * adress = [NSString stringWithFormat:@
"國家:%@\n省:%@\n市:%@\n街道:%@\n郵編:%@"
,[temDic valueForKey:(NSString*)kABPersonAddressCountryKey],[temDic valueForKey:(NSString*)kABPersonAddressStateKey],[temDic valueForKey:(NSString*)kABPersonAddressCityKey],[temDic valueForKey:(NSString*)kABPersonAddressStreetKey],[temDic valueForKey:(NSString*)kABPersonAddressZIPKey]];
}
//獲取當前聯絡人頭像圖片
NSData*userImage=(__bridge NSData*)(ABPersonCopyImageData(people));
//獲取當前聯絡人紀念日
NSMutableArray * dateArr = [[NSMutableArray alloc]init];
ABMultiValueRef dates= ABRecordCopyValue(people, kABPersonDateProperty);
for
(NSInteger j=0; j<ABMultiValueGetCount(dates); j++) {
//獲取紀念日日期
NSDate * data =(__bridge NSDate*)(ABMultiValueCopyValueAtIndex(dates, j));
//獲取紀念日名稱
NSString * str =(__bridge NSString*)(ABMultiValueCopyLabelAtIndex(dates, j));
NSDictionary * temDic = [NSDictionary dictionaryWithObject:data forKey:str];
[dateArr addObject:temDic];
}
一點擴充套件:相同的方法,可以獲取關聯人資訊,社交資訊,郵箱資訊,各種型別的電話資訊,欄位如下:
//相關人,組織欄位
const
ABPropertyID kABPersonKindProperty;
const
CFNumberRef kABPersonKindPerson;
const
CFNumberRef kABPersonKindOrganization;
// 電話相關欄位
AB_EXTERN
const
ABPropertyID kABPersonPhoneProperty;
AB_EXTERN
const
CFStringRef kABPersonPhoneMobileLabel;
AB_EXTERN
const
CFStringRef kABPersonPhoneIPhoneLabel
AB_EXTERN
const
CFStringRef kABPersonPhoneMainLabel;
AB_EXTERN
const
CFStringRef kABPersonPhoneHomeFAXLabel;
AB_EXTERN
const
CFStringRef kABPersonPhoneWorkFAXLabel;
AB_EXTERN
const
CFStringRef kABPersonPhoneOtherFAXLabel
AB_EXTERN
const
CFStringRef kABPersonPhonePagerLabel;
// 即時聊天資訊相關欄位
AB_EXTERN
const
ABPropertyID kABPersonInstantMessageProperty;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceKey;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceYahoo;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceJabber;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceMSN;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceICQ;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceAIM;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceQQ
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceGoogleTalk;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceSkype;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceFacebook;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageServiceGaduGadu;
AB_EXTERN
const
CFStringRef kABPersonInstantMessageUsernameKey;
// 個人網頁相關欄位
AB_EXTERN
const
ABPropertyID kABPersonURLProperty;
AB_EXTERN
const
CFStringRef kABPersonHomePageLabel;
//相關人姓名欄位
AB_EXTERN
const
ABPropertyID kABPersonRelatedNamesProperty;
AB_EXTERN
const
CFStringRef kABPersonFatherLabel;
// Father
AB_EXTERN
const
CFStringRef kABPersonMotherLabel;
// Mother
AB_EXTERN
const
CFStringRef kABPersonParentLabel;
// Parent
AB_EXTERN
const
CFStringRef kABPersonBrotherLabel;
// Brother
AB_EXTERN
const
CFStringRef kABPersonSisterLabel;
// Sister
AB_EXTERN
const
CFStringRef kABPersonChildLabel;
// Child
AB_EXTERN
const
CFStringRef kABPersonFriendLabel;
// Friend
AB_EXTERN
const
CFStringRef kABPersonSpouseLabel;
// Spouse
AB_EXTERN
const
CFStringRef kABPersonPartnerLabel;
// Partner
AB_EXTERN
const
CFStringRef kABPersonAssistantLabel;
// Assistant
AB_EXTERN
const
CFStringRef kABPersonManagerLabel;
// Manager
三、通訊錄“寫”的相關操作
看到上面讀取資訊的程式碼,你可能覺得一陣目炫,其實只是欄位比較長,邏輯還是很簡單的,同樣,寫的操作與之類似,建立,修改,刪除,是我們對通訊錄“寫”的常用操作。
1、建立一個聯絡人
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//建立一個聯絡人引用
ABRecordRef person = ABPersonCreate();
NSString *firstName = @ "哈" ;
NSString *lastName = @ "哈" ;
// 電話號碼陣列
NSArray *phones = [NSArray arrayWithObjects:@ "123" ,@ "456" ,nil];
// 電話號碼對應的名稱
NSArray *labels = [NSArray arrayWithObjects:@ "iphone" ,@ "home" ,nil];
//這裡的欄位和上面的欄位完全相同
// 設定名字屬性
ABRecordSetValue(person, kABPersonFirstNameProperty,(__bridge CFStringRef)firstName, NULL);
// 設定姓氏屬性
ABRecordSetValue(person, kABPersonLastNameProperty, (__bridge CFStringRef)lastName, NULL);
// 設定生日屬性
ABRecordSetValue(person, kABPersonBirthdayProperty,(__bridge CFDateRef)birthday, NULL);
// 字典引用
ABMultiValueRef dic =ABMultiValueCreateMutable(kABMultiStringPropertyType);
// 新增電話號碼與其對應的名稱內容
for ( int i = 0; i < [phones count]; i ++) {
ABMultiValueIdentifier obj = ABMultiValueAddValueAndLabel(dic,(__bridge CFStringRef)[phones objectAtIndex:i], (__bridge CFStringRef)[labels objectAtIndex:i], &obj);
}
// 設定phone屬性
ABRecordSetValue(person, kABPersonPhoneProperty, dic, NULL);
// 將新建的聯絡人新增到通訊錄中
ABAddressBookAddRecord(addBook, person, NULL);
// 儲存通訊錄資料
ABAddressBookSave(addBook, NULL);
|
2、修改聯絡人
修改聯絡人的操作就是將獲取和新增和在一起,先獲取到相應的聯絡人引用,重設其屬性欄位即可。
3.刪除聯絡人
?1 2 3 4 5 6 7 8 9 10 11 12 13 |
//獲取所有聯絡人
NSArray *array = (__bridge NSArray*)ABAddressBookCopyArrayOfAllPeople(addBook);
// 遍歷所有的聯絡人
for (id obj in array) {
ABRecordRef people = (__bridge ABRecordRef)obj;
NSString *firstName = (__bridge NSString*)ABRecordCopyValue(people, kABPersonFirstNameProperty);
NSString *lastName = (__bridge NSString*)ABRecordCopyValue(people, kABPersonLastNameProperty);
if ([firstName isEqualToString:@ "哈" ] &&[lastName isEqualToString:@ "哈" ]) {
ABAddressBookRemoveRecord(addBook, people,NULL);
}
}
// 儲存修改的通訊錄物件
ABAddressBookSave(addBook, NULL);
|
四、重中之重-關於記憶體管理
上面的程式碼為了演示方便,建立的全部引用都沒有釋放,勢必是造成記憶體洩露,在我們用ABAddressBookCreate()建立一個引用物件時,切記無論ARC還MRC,要用CFRelease()進行釋放引用,例如上面的例子,我們需要加上這句程式碼
CFRelease(addBook);
如果你耐心的看到了這裡,我想你一定明白了我為什麼不在前邊的程式碼裡說明這個問題,因為在ARC專案普及的現在,這的確是重中之重。