讀取通信錄中的聯(lián)系人一般的過(guò)程是先查找聯(lián)系人記錄,然后再訪(fǎng)問(wèn)記錄的屬性,屬性又可以分為單值屬性和多值屬性。通過(guò)下面例子介紹聯(lián)系人的查詢(xún),以及單值屬性和多值屬性的訪(fǎng)問(wèn),還有讀取聯(lián)系人中的圖片數(shù)據(jù)。
目前創(chuàng)新互聯(lián)已為千余家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、綿陽(yáng)服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、延安網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶(hù)導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶(hù)和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。
本案例是從iOS設(shè)備上讀取通訊錄中的聯(lián)系人,并將其顯示在一個(gè)表視圖中,可以進(jìn)行查詢(xún),點(diǎn)擊聯(lián)系人進(jìn)入詳細(xì)信息畫(huà)面。訪(fǎng)問(wèn)通訊錄的應(yīng)用必須要做的兩件事情:
1、添加AddressBook和AddressBookUI框架
為工程添加AddressBook.framework和AddressBookUI.framework
2、引入頭文件
在需要訪(fǎng)問(wèn)通訊錄類(lèi)的頭文件中引入下面頭文件:
#import
#import
查詢(xún)聯(lián)系人記錄
在從通信錄數(shù)據(jù)庫(kù)查詢(xún)聯(lián)系人數(shù)據(jù)是無(wú)法使用SQL語(yǔ)句,只能通過(guò)ABAddressBookCopyArrayOfAllPeople和ABAddressBookCopyPeopleWithName函數(shù)獲得,它們的定義如下:
CFArrayRef ABAddressBookCopyArrayOfAllPeople ( ABAddressBookRef addressBook ); CFArrayRef ABAddressBookCopyPeopleWithName ( ABAddressBookRef addressBook, CFStringRef name );
ABAddressBookCopyArrayOfAllPeople函數(shù)是查詢(xún)所有的聯(lián)系人數(shù)據(jù)。ABAddressBookCopyPeopleWithName函數(shù)是通過(guò)人名查詢(xún)通訊錄中的聯(lián)系人,其中的name參數(shù)就是查詢(xún)的前綴關(guān)鍵字。兩個(gè)函數(shù)中都有addressBook參數(shù),它是我們要查詢(xún)的通訊錄對(duì)象,其創(chuàng)建使用ABAddressBookCreateWithOptions函數(shù)(在iOS6之前是ABAddressBookCreate函數(shù)),它的定義:
ABAddressBookRef ABAddressBookCreateWithOptions ( CFDictionaryRef options, CFErrorRef* error );
options參數(shù)是保留參數(shù),目前沒(méi)有采用,使用時(shí)候可以傳遞NULL值。error是錯(cuò)誤對(duì)象,包含錯(cuò)誤信息。
下面是我們代碼中有關(guān)系查詢(xún)的部分,先看一下ViewController.h:
#import#import #import ”DetailViewController.h” @interface ViewController : UITableViewController @property (nonatomic, strong) NSArray *listContacts; - (void)filterContentForSearchText:(NSString*)searchText; @end
屬性listContacts是裝載聯(lián)系人記錄數(shù)組集合,filterContentForSearchText:方法是用來(lái)過(guò)濾聯(lián)系人信息的方法,也就是查詢(xún)方法。
ViewController.m中的viewDidLoad方法:
- (void)viewDidLoad { [super viewDidLoad]; CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); ① ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { ② if (granted) { //查詢(xún)所有 [self filterContentForSearchText:@""]; ③ } }); CFRelease(addressBook); ④ }
在viewDidLoad方法中首先在第①行代碼處使用ABAddressBookCreateWithOptions函數(shù)創(chuàng)建addressBook對(duì)象,然后在第②行又調(diào)用了函數(shù)ABAddressBookRequestAccessWithCompletion,這個(gè)函數(shù)用于向用戶(hù)請(qǐng)求訪(fǎng)問(wèn)通訊錄數(shù)據(jù)庫(kù),如果是第一次訪(fǎng)問(wèn),則會(huì)彈出一個(gè)用戶(hù)授權(quán)對(duì)話(huà)框,如果用戶(hù)授權(quán)可以訪(fǎng)問(wèn)則會(huì)調(diào)用下面的代碼塊。
^(bool granted, CFErrorRef error) { if (granted) { } });
由于請(qǐng)求和代碼塊的回調(diào)都是異步的,你會(huì)發(fā)現(xiàn)表視圖畫(huà)面先出現(xiàn),然后過(guò)一會(huì)兒才有查詢(xún)出來(lái)的結(jié)果。在iOS6之后這個(gè)請(qǐng)求過(guò)程必須有的,否則無(wú)法訪(fǎng)問(wèn)通訊錄數(shù)據(jù)庫(kù)。
ViewController.m中的filterContentForSearchText:查詢(xún)方法:
- (void)filterContentForSearchText:(NSString*)searchText { //如果沒(méi)有授權(quán)則退出 if (ABAddressBookGetAuthorizationStatus() != kABAuthorizationStatusAuthorized) { return ; } CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); if([searchText length]==0) { //查詢(xún)所有 self.listContacts = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook)); } else { //條件查詢(xún) CFStringRef cfSearchText = (CFStringRef)CFBridgingRetain(searchText); self.listContacts = CFBridgingRelease(ABAddressBookCopyPeopleWithName(addressBook, cfSearchText)); CFRelease(cfSearchText); } [self.tableView reloadData]; CFRelease(addressBook); }
在該方法中實(shí)現(xiàn)查詢(xún),ABAddressBookGetAuthorizationStatus()函數(shù)返回應(yīng)用的授權(quán)狀態(tài),其中kABAuthorizationStatusAuthorized常量代表用戶(hù)已經(jīng)授權(quán),在沒(méi)有授權(quán)情況下該方法不進(jìn)行任何處理。ABAddressBookCopyArrayOfAllPeople函數(shù)是查詢(xún)所有數(shù)據(jù),ABAddressBookCopyPeopleWithName函數(shù)是根據(jù)條件查詢(xún),返回值是CFArrayRef類(lèi)型,不能直接賦值給listContacts(NSArray*類(lèi)型)屬性,處理方式一般如下兩種:
self.listContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook) ;
或
self.listContacts = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
(__bridge NSArray *)方式不會(huì)轉(zhuǎn)讓對(duì)象所有權(quán),只是簡(jiǎn)單強(qiáng)制轉(zhuǎn)化。CFBridgingRelease函數(shù)實(shí)現(xiàn)的是Core Foundation類(lèi)型到Foundation類(lèi)型轉(zhuǎn)化并把對(duì)象所有權(quán)轉(zhuǎn)讓ARC(自動(dòng)管理引用計(jì)數(shù)),因此不需要釋放屬性listContacts對(duì)應(yīng)的成員變量。類(lèi)似還有CFBridgingRetain函數(shù),實(shí)現(xiàn)的是Foundation類(lèi)型到Core Foundation類(lèi)型轉(zhuǎn)化, 并把對(duì)象所有權(quán)轉(zhuǎn)讓調(diào)用者,因此需要釋放這個(gè)對(duì)象,代碼如下:
CFStringRef cfSearchText = (CFStringRef)CFBridgingRetain(searchText);
self.listContacts = CFBridgingRelease(ABAddressBookCopyPeopleWithName(addressBook, cfSearchText));
CFRelease(cfSearchText);
CFStringRef cfSearchText = (CFStringRef)CFBridgingRetain(searchText); self.listContacts = CFBridgingRelease(ABAddressBookCopyPeopleWithName(addressBook, cfSearchText)); CFRelease(cfSearchText);
最后在第④行調(diào)用CFRelease(addressBook)函數(shù)釋放addressBook對(duì)象,Core Foundation框架中的數(shù)據(jù)類(lèi)型內(nèi)存管理是不受ARC管理的,但是與Foundation框架的MRC管理類(lèi)似,需要手動(dòng)釋放,CFRelease函數(shù)就是相當(dāng)于Foundation框架中的release(或autorelease)方法。
ViewController.m中的SearchBar查詢(xún)相關(guān)方法:
#pragma mark –UISearchBarDelegate 協(xié)議方法
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar { //查詢(xún)所有 [self filterContentForSearchText:@""]; } #pragma mark - UISearchDisplayController Delegate Methods //當(dāng)文本內(nèi)容發(fā)生改變時(shí)候,向表視圖數(shù)據(jù)源發(fā)出重新加載消息 - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { [self filterContentForSearchText:searchString]; //YES情況下表視圖可以重新加載 return YES; }
讀取單值屬性
在一條聯(lián)系人記錄中,有很多屬性,這些屬性有單值屬性和多值屬性,單值屬性是只有一個(gè)值的屬性,如:姓氏、名字等,它們是由下面常量定義的:
kABPersonFirstNameProperty,名字
kABPersonLastNameProperty,姓氏
kABPersonMiddleNameProperty,中間名
kABPersonPrefixProperty,前綴
kABPersonSuffixProperty,后綴
kABPersonNicknameProperty,昵稱(chēng)
kABPersonFirstNamePhoneticProperty,名字漢語(yǔ)拼音或音標(biāo)
kABPersonLastNamePhoneticProperty,姓氏漢語(yǔ)拼音或音標(biāo)
q kABPersonMiddleNamePhoneticProperty,中間名漢語(yǔ)拼音或音標(biāo)
kABPersonOrganizationProperty,組織名
kABPersonJobTitleProperty,頭銜
kABPersonDepartmentProperty,部門(mén)
kABPersonNoteProperty,備注
讀取記錄屬性函數(shù)是ABRecordCopyValue,ABRecordCopyValue函數(shù)的定義如下:
CFTypeRef ABRecordCopyValue (
ABRecordRef record,
ABPropertyID property
);
ABRecordRef參數(shù)是記錄對(duì)象,ABPropertyID是屬性ID,就是上面的常量kABPersonFirstNameProperty等。返回值類(lèi)型是CFTypeRef,它是Core Foundation類(lèi)型的“泛型”,可以代表任何的Core Foundation類(lèi)型。
ViewController.m中的tableView:cellForRowAtIndexPath:方法,主要實(shí)現(xiàn)了訪(fǎng)問(wèn)單值屬性:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @”Cell”; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } ABRecordRef thisPerson = CFBridgingRetain([self.listContacts objectAtIndex:[indexPath row]]); ① NSString *firstName = CFBridgingRelease(ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty)); ② firstName = firstName != nil?firstName:@”"; NSString *lastName = CFBridgingRelease(ABRecordCopyValue(thisPerson, kABPersonLastNameProperty)); ③ lastName = lastName != nil?lastName:@”"; cell.textLabel.text = [NSString stringWithFormat:@"%@ %@",firstName,lastName]; CFRelease(thisPerson); return cell; }
第①行ABRecordRef thisPerson = CFBridgingRetain([self.listContacts objectAtIndex:[indexPath row]])語(yǔ)句是從NSArray*集合中取出一個(gè)元素,并且轉(zhuǎn)化為Core Foundation類(lèi)型的ABRecordRef類(lèi)型。CFBridgingRelease(ABRecordCopyValue(thisPerson, kABPersonFirstNameProperty))語(yǔ)句是將名字屬性取出來(lái),轉(zhuǎn)化為NSString*類(lèi)型。最后CFRelease(thisPerson)是釋放ABRecordRef對(duì)象。
此外,為了把選中的聯(lián)系人傳遞給詳細(xì)畫(huà)面,我們需要獲得選中記錄的ID,然后把ID傳遞到詳細(xì)畫(huà)面,這個(gè)過(guò)程處理是在ViewController.m中的 prepareForSegue:方法完成的:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@”showDetail”]) { NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; ABRecordRef thisPerson = CFBridgingRetain([self.listContacts objectAtIndex:[indexPath row]]); DetailViewController *detailViewController = [segue destinationViewController]; ABRecordID personID = ABRecordGetRecordID(thisPerson); ① NSNumber *personIDAsNumber = [NSNumber numberWithInt:personID]; ② detailViewController.personIDAsNumber = personIDAsNumber; ③ CFRelease(thisPerson); ④ } }
其中第①行代碼調(diào)用函數(shù)ABRecordGetRecordID是獲取選中記錄的ID,其中ID為ABRecordID類(lèi)型。為了傳遞這個(gè)ID給DetailViewController視圖控制器,DetailViewController視圖控制器定義了personIDAsNumber屬性,在第③行將ID給personIDAsNumber屬性。DetailViewController.h代碼如下:
#import
#import
@interface DetailViewController : UITableViewController
@property (weak, nonatomic) IBOutlet UIImageView *p_w_picpathView;
@property (weak, nonatomic) IBOutlet UILabel *lblName;
@property (weak, nonatomic) IBOutlet UILabel *lblMobile;
@property (weak, nonatomic) IBOutlet UILabel *lblIPhone;
@property (weak, nonatomic) IBOutlet UILabel *lblWorkEmail;
@property (weak, nonatomic) IBOutlet UILabel *lblHomeEmail;
@property (strong, nonatomic) NSNumber* personIDAsNumber;
@end
personIDAsNumber屬性為NSNumber*類(lèi)型。
讀取多值屬性
多值屬性是包含多個(gè)值的集合類(lèi)型,如:電話(huà)號(hào)碼、Email、URL等,它們主要是由下面常量定義的:
kABPersonPhoneProperty,電話(huà)號(hào)碼屬性,kABMultiStringPropertyType類(lèi)型多值屬性;
kABPersonEmailProperty,Email屬性,kABMultiStringPropertyType類(lèi)型多值屬性;
kABPersonURLProperty,URL屬性,kABMultiStringPropertyType類(lèi)型多值屬性;
kABPersonRelatedNamesProperty,親屬關(guān)系人屬性,kABMultiStringPropertyType類(lèi)型多值屬性;
kABPersonAddressProperty,地址屬性,kABMultiDictionaryPropertyType類(lèi)型多值屬性;
kABPersonInstantMessageProperty,即時(shí)聊天屬性,kABMultiDictionaryPropertyType類(lèi)型多值屬性;
kABPersonSocialProfileProperty,社交賬號(hào)屬性,kABMultiDictionaryPropertyType類(lèi)型多值屬性;
在多值屬性中包含了label(標(biāo)簽)、value(值)和ID等部分,其中標(biāo)簽和值都是可以重復(fù)的,而ID是不能重復(fù)的
多值屬性訪(fǎng)問(wèn)方式與單值屬性訪(fǎng)問(wèn)類(lèi)似都使用ABRecordCopyValue函數(shù)。不同的是多值屬性訪(fǎng)問(wèn)返回值是ABMultiValueRef,然后要使用ABMultiValueCopyArrayOfAllValues函數(shù)從ABMultiValueRef對(duì)象中獲取數(shù)組CFArrayRef集合。ABMultiValueCopyArrayOfAllValues函數(shù)的定義如下:
CFArrayRef ABMultiValueCopyArrayOfAllValues ( ABMultiValueRef multiValue ); ABMultiValueCopyLabelAtIndex函數(shù)可以從ABMultiValueRef對(duì)象中返回標(biāo)簽,其定義如下: CFStringRef ABMultiValueCopyLabelAtIndex ( ABMultiValueRef multiValue, CFIndex index ); 參數(shù)multiValue是ABMultiValueRef對(duì)象,index是查找標(biāo)簽的索引。 ABMultiValueGetIdentifierAtIndex函數(shù)可以從ABMultiValueRef對(duì)象中返回ID,其定義如下: ABMultiValueIdentifier ABMultiValueGetIdentifierAtIndex ( ABMultiValueRef multiValue, CFIndex index );
在DetailViewController.m文件viewDidLoad方法中取得Email多值屬性,其代碼如下:
ABMultiValueRef emailsProperty = ABRecordCopyValue(person, kABPersonEmailProperty); NSArray* emailsArray = CFBridgingRelease(ABMultiValueCopyArrayOfAllValues(emailsProperty)); for(int index = 0; index< [emailsArray count]; index++){ NSString *email = [emailsArray objectAtIndex:index]; NSString *emailLabel = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(emailsProperty, index)); if ([emailLabel isEqualToString:(NSString*)kABWorkLabel]) { [self.lblWorkEmail setText:email]; } else if ([emailLabel isEqualToString:(NSString*)kABHomeLabel]) { [self.lblHomeEmail setText:email]; } else { NSLog(@”%@: %@”, @”其它Email”, email); } } CFRelease(emailsProperty);
其中ABMultiValueCopyArrayOfAllValues(emailsProperty))語(yǔ)句是從emailsProperty屬性中取出數(shù)組集合。kABWorkLabel和kABHomeLabel都是Email多值屬性的標(biāo)簽。kABWorkLabel是工作Email標(biāo)簽和kABHomeLabel是家庭Email標(biāo)簽,另外還有kABOtherLabel,它是Email標(biāo)簽。最后emailsProperty需要釋放。
DetailViewController.m中的viewDidLoad方法中取得電話(huà)號(hào)碼多值屬性代碼如下:
ABMultiValueRef phoneNumberProperty = ABRecordCopyValue(person, kABPersonPhoneProperty); NSArray* phoneNumberArray = CFBridgingRelease(ABMultiValueCopyArrayOfAllValues(phoneNumberProperty)); for(int index = 0; index< [phoneNumberArray count]; index++){ NSString *phoneNumber = [phoneNumberArray objectAtIndex:index]; NSString *phoneNumberLabel = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(phoneNumberProperty, index)); if ([phoneNumberLabel isEqualToString:(NSString*)kABPersonPhoneMobileLabel]) { [self.lblMobile setText:phoneNumber]; } else if ([phoneNumberLabel isEqualToString:(NSString*)kABPersonPhoneIPhoneLabel]) { [self.lblIPhone setText:phoneNumber]; } else { NSLog(@”%@: %@”, @”其它電話(huà)”, phoneNumber); } } CFRelease(phoneNumberProperty);
kABPersonPhoneMobileLabel和kABPersonPhoneIPhoneLabel都是電話(huà)號(hào)碼屬性的標(biāo)簽。kABPersonPhoneMobileLabel是移動(dòng)電話(huà)號(hào)碼標(biāo)簽,kABPersonPhoneIPhoneLabel是iPhone電話(huà)號(hào)碼標(biāo)簽。此外還有:
kABPersonPhoneMainLabel,主要電話(huà)號(hào)碼標(biāo)簽;
kABPersonPhoneHomeFAXLabel,家庭傳真電話(huà)號(hào)碼標(biāo)簽;
kABPersonPhoneWorkFAXLabel,工作傳真電話(huà)號(hào)碼標(biāo)簽;
kABPersonPhonePagerLabel,尋呼機(jī)號(hào)碼標(biāo)簽。
11.2.4 讀取圖片屬性
通訊錄中的聯(lián)系人可以有一個(gè)圖片,讀取聯(lián)系人圖片的相關(guān)函數(shù)有ABPersonCopyImageData和ABPersonHasImageData等。ABPersonCopyImageData可以讀取聯(lián)系人圖片函數(shù),它的定義如下:
CFDataRef ABPersonCopyImageData (
ABRecordRef person
);
它的返回類(lèi)型是CFDataRef,與之對(duì)應(yīng)的Foundation框架類(lèi)型是NSData*。ABPersonHasImageData函數(shù)用于判斷聯(lián)系人是否有圖片,它的定義如下:
bool ABPersonHasImageData ( ABRecordRef person );
DetailViewController.m中的viewDidLoad方法中取得聯(lián)系人圖片代碼如下:
if (ABPersonHasImageData(person)) {
NSData *photoData = CFBridgingRelease(ABPersonCopyImageData(person)); if(photoData){ [self.p_w_picpathView setImage:[UIImage p_w_picpathWithData:photoData]]; } }
ABPersonCopyImageData取出的是CFDataRef類(lèi)型,將其轉(zhuǎn)化為NSData*,再使用UIImage的構(gòu)造方法p_w_picpathWithData:構(gòu)建UIImage對(duì)象,然后再把UIImage對(duì)象賦值給p_w_picpathView圖片控件。