蘋果給用戶提供了自己的通訊錄,但是根據業務的需求,需要自定義通訊錄,我們就需要根據業務需求來自定義
首先我們需要知道蘋果的提供的一些Foundation、UIKit框架,了解其中的一些特性,可以打開手機查看蘋果系統提供的
原生的通訊錄,可以看到:
1.搜索框
2.右側搜索條
3.聯系人分組
4.添加聯系人
5.獲取聯系人頭像及聯系方式
根據需求,可以總結出自定義通訊錄需要做的一些功能,一項大的功能可以差分成一些小的功能,然後
一個一個實現,將復雜的問題差分成小問題解決。
1.自定義搜索框
2.獲取首字母
3.權限判斷
4.排序
5.自定義搜索
6.自定義聯系人界面(考慮多值的情況,獲取通訊錄頭像)
簡答介紹下排序:
IOS項目中會用到對通訊錄的聯系人或是會員按姓名為關鍵字排序,因為NSArray並不直接支持對漢字的排序,這就要通過將漢字轉換成拼音完成按A~Z的排序,這看起來是個頭疼的問題,因為牽扯到漢字轉為拼音,獲取漢字的首字的首字母,如將“王”變成“W”。 函數原理是:我們知道,在Objective C語言中,字符串是以unicode進行編碼的。在unicode字符集中,漢字的編碼范圍為4E00 到 9FA5 之間(即從第19968開始的20902個字符是vc4PAwB0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHnsPj63Pjn4Pjm4n1c1n1n1rf" rel="nofollow" target="_blank">中文簡體字符)。我們把這些字符的拼音首字母按照順序都存放在一個char數組中。當我們查找一個漢字的拼音首字母時,只需把這個漢字的unicode碼(即char強制轉換為int)減去19968,然後用這個數字作為索引去找char數組中存放的字母即可。給出項目的源碼,注釋很清楚。代碼如:
RYAddressBook.h
#import#import "RYPersonInfo.h" typedef void (^AddressBookBlock) (NSArray *personInfos); @interface RYAddressBook : NSObject /** * 將數字轉化為字母 0~26 1~25=a~z 26=# */ NSString* SpellFromIndex(int index); /** * 獲取索引 */ int Index(NSString *firstSpell); /** * 獲取用戶所有通訊錄信息 * * @return 所有通訊錄數據信息數組 */ + (void)getPersonInfo:(AddressBookBlock)addressBookBlock; /** * 根據關鍵字匹配所有用戶信息 * * @param keyWord 匹配關鍵字 * * @return 匹配到的通訊錄數據信息數組 */ + (void)searchPersonInfo:(NSString *)keyWord addressBookBlock:(AddressBookBlock)addressBookBlock; /** * 根據姓名進行數組的重排序 * * @param personInfos 獲取的通訊錄數據信息數組 */ + (NSArray *)sortPersonInfos:(NSArray *)personInfos; @end
RYAddressBook.m
#import "RYAddressBook.h" @interface RYAddressBook () @property (nonatomic, copy) AddressBookBlock addressBookBlock; @end @implementation RYAddressBook NSString* SpellFromIndex(int index) { if (index == 26) return @"#"; else return [NSString stringWithFormat:@"%c", [@"A" characterAtIndex:0]+index]; } int Index(NSString *firstSpell) { int i = [firstSpell characterAtIndex:0] - [@"a" characterAtIndex:0]; if ([firstSpell isEqualToString:@"#"] || i < 0 || i > 26) { return 26; } return [firstSpell characterAtIndex:0] - [@"a" characterAtIndex:0]; } /** * 獲取用戶所有通訊錄信息 */ + (void)getPersonInfo:(AddressBookBlock)addressBookBlock { [[self alloc] getPersonInfo:addressBookBlock]; } /** * 根據關鍵字匹配所有用戶信息 */ + (void)searchPersonInfo:(NSString *)keyWord addressBookBlock:(AddressBookBlock)addressBookBlock { [[self alloc] searchPersonInfo:keyWord addressBookBlock:addressBookBlock]; } /** * 根據姓名進行數組的重排序 */ + (NSArray *)sortPersonInfos:(NSArray *)personInfos { return [[self alloc] sortPersonInfos:personInfos]; } - (void)getPersonInfo:(AddressBookBlock)addressBookBlock { self.addressBookBlock = addressBookBlock; [self searchPersonInfo:@""]; } - (void)searchPersonInfo:(NSString *)keyWord addressBookBlock:(AddressBookBlock)addressBookBlock { self.addressBookBlock = addressBookBlock; [self searchPersonInfo:keyWord]; } - (NSArray *)sortPersonInfos:(NSArray *)personInfos { if (![personInfos isKindOfClass:[NSArray class]]) { return nil; } NSMutableArray *arr = [NSMutableArray array]; for (int i = 0; i < 27; i++) { [arr addObject:[NSMutableArray array]]; } for (NSObject *obj in personInfos) { if (![obj isKindOfClass:[RYPersonInfo class]]) { continue; } RYPersonInfo *personInfo = (RYPersonInfo *)obj; NSMutableArray *subArr = [arr objectAtIndex:Index(personInfo.firstSpell)]; [subArr addObject:personInfo]; } return arr; } /** * 根據關鍵字查詢通訊錄信息 */ - (void)searchPersonInfo:(NSString *)keyWord { CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); // 開始查詢通訊錄 ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { if (granted) { [self filterContentForSearchText:keyWord]; } }); } /** * 開始匹配通訊錄信息 */ - (void)filterContentForSearchText:(NSString*)searchText { //如果沒有授權則退出 if (ABAddressBookGetAuthorizationStatus() != kABAuthorizationStatusAuthorized) { return; } NSArray *blockArray = [NSArray array]; CFErrorRef error = NULL; ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); if([searchText length]==0) { //查詢所有 blockArray = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook); } else { //條件查詢 CFStringRef cfSearchText = (CFStringRef)CFBridgingRetain(searchText); blockArray = CFBridgingRelease(ABAddressBookCopyPeopleWithName(addressBook, cfSearchText)); CFRelease(cfSearchText); } // 類型轉換 blockArray = transformElements(blockArray); // 返回BlockArray self.addressBookBlock(blockArray); } /** * 將所有元素轉化為JXPersonInfo類型數組 */ NSArray* transformElements(NSArray* arr) { NSMutableArray *rtnArray = [NSMutableArray array]; for (int i = 0; i < arr.count; i++) { ABRecordRef recordRef = CFBridgingRetain([arr objectAtIndex:i]); RYPersonInfo *personInfo = [RYPersonInfo personInfoWithABRecordRef:recordRef]; [rtnArray addObject:personInfo]; } return rtnArray; } @end
RYPersonInfo.h
#import#import @interface RYPersonInfo : NSObject /** * 單值信息 */ #define PROPERTY_STR_READONLY(name) @property (nonatomic, copy) NSString *name; // 姓 PROPERTY_STR_READONLY(firstName) // 名 PROPERTY_STR_READONLY(lastName) // 中間名 PROPERTY_STR_READONLY(middlename) // 全名 PROPERTY_STR_READONLY(fullName) // 搜索索引 PROPERTY_STR_READONLY(firstSpell) // 前綴 PROPERTY_STR_READONLY(prefix) // 後綴 PROPERTY_STR_READONLY(suffix) // 昵稱 PROPERTY_STR_READONLY(nickname) // 姓_音標 PROPERTY_STR_READONLY(firstnamePhonetic) // 名_音標 PROPERTY_STR_READONLY(lastnamePhonetic) // 中間名_音標 PROPERTY_STR_READONLY(middlenamePhonetic) // 公司 PROPERTY_STR_READONLY(organization) // 工作 PROPERTY_STR_READONLY(jobtitle) // 部門 PROPERTY_STR_READONLY(department) // 生日 PROPERTY_STR_READONLY(birthday) // 備忘錄 PROPERTY_STR_READONLY(note) // 第一次創建用戶信息的時間 PROPERTY_STR_READONLY(firstknow) // 最後一次更改用戶信息的時間 PROPERTY_STR_READONLY(lastknow) // 名片類型(company/person) PROPERTY_STR_READONLY(kind) // 多值信息 #define PROPERTY_ARR_READONLY(name) @property (nonatomic, strong) NSArray *name; // 郵箱 PROPERTY_ARR_READONLY(email) // 地址 PROPERTY_ARR_READONLY(address) // 日期 PROPERTY_ARR_READONLY(dates) // iMessage PROPERTY_ARR_READONLY(iMessage) // 電話號碼 PROPERTY_ARR_READONLY(phone) // URL鏈接 PROPERTY_ARR_READONLY(url) #define PROPERTY_IMG_READONLY(name) @property (nonatomic, strong) UIImage *name; // 圖片 //PROPERTY_IMG_READONLY(image) /** * 初始化方法 * * @param ref 聯系人屬性 * * @return 實例對象 */ - (id)initWithABRecordRef:(ABRecordRef)ref; /** * 初始化類方法 * * @param ref 聯系人屬性 * * @return 實例對象 */ + (id)personInfoWithABRecordRef:(ABRecordRef)ref; @end
RYPersonInfo.m
#import "RYPersonInfo.h" #define nullStrToEmpty(str) \ [str rangeOfString:@"null"].location==0? @"" : str /** * 單值信息 */ #define GET_PROPERTY_METHOD(property, property_key) \ - (NSString *)property {\ return (NSString *)CFBridgingRelease(ABRecordCopyValue(_recordRef, property_key));\ } /** * 多值信息 */ #define DICT_ADD_STR_FOR_KEY(dict, str, key) \ if (str) {\ [dict setObject:str forKey:key];\ } #define GET_PROPERTY_SIGLE_VALUE_METHOD(property, property_key)\ - (NSArray *)property\ {\ NSMutableArray *rtnArray = [NSMutableArray array];\ \ ABMultiValueRef ref = ABRecordCopyValue(_recordRef, property_key);\ long count = ABMultiValueGetCount(ref);\ for (int i = 0; i < count; i++)\ {\ NSString* label = (__bridge NSString*)ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex(ref, i));\ NSString* content = (__bridge NSString*)ABMultiValueCopyValueAtIndex(ref, i);\ NSMutableDictionary *dict = [NSMutableDictionary dictionary];\ DICT_ADD_STR_FOR_KEY(dict, content, label);\ \ [rtnArray addObject:dict];\ }\ return rtnArray;\ } @interface RYPersonInfo () @property (nonatomic , assign)ABRecordRef recordRef; @end @implementation RYPersonInfo - (id)initWithABRecordRef:(ABRecordRef)ref { if (self = [super init]) { _recordRef = ref; } return self; } + (id)personInfoWithABRecordRef:(ABRecordRef)ref { return [[[self class] alloc] initWithABRecordRef:ref]; } GET_PROPERTY_METHOD( firstName , kABPersonFirstNameProperty); GET_PROPERTY_METHOD( lastName , kABPersonLastNameProperty); GET_PROPERTY_METHOD( middlename , kABPersonMiddleNameProperty); GET_PROPERTY_METHOD( prefix , kABPersonPrefixProperty); GET_PROPERTY_METHOD( suffix , kABPersonSuffixProperty); GET_PROPERTY_METHOD( nickname , kABPersonNicknameProperty); GET_PROPERTY_METHOD( organization , kABPersonOrganizationProperty); GET_PROPERTY_METHOD( jobtitle , kABPersonJobTitleProperty); GET_PROPERTY_METHOD( department , kABPersonDepartmentProperty); GET_PROPERTY_METHOD( birthday , kABPersonBirthdayProperty); GET_PROPERTY_METHOD( note , kABPersonNoteProperty); GET_PROPERTY_METHOD( firstknow , kABPersonCreationDateProperty); GET_PROPERTY_METHOD( lastknow , kABPersonModificationDateProperty); GET_PROPERTY_METHOD( firstnamePhonetic , kABPersonFirstNamePhoneticProperty); GET_PROPERTY_METHOD( lastnamePhonetic , kABPersonLastNamePhoneticProperty); GET_PROPERTY_METHOD( middlenamePhonetic, kABPersonMiddleNamePhoneticProperty); GET_PROPERTY_SIGLE_VALUE_METHOD(email, kABPersonEmailProperty) GET_PROPERTY_SIGLE_VALUE_METHOD(dates, kABPersonDateProperty) GET_PROPERTY_SIGLE_VALUE_METHOD(url , kABPersonURLProperty) GET_PROPERTY_SIGLE_VALUE_METHOD(phone, kABPersonPhoneProperty) - (NSString *)kind { NSString *rtnStr = nil; CFNumberRef recordType = ABRecordCopyValue(_recordRef, kABPersonKindProperty); if (recordType == kABPersonKindOrganization) { rtnStr = @"company"; } else { rtnStr = @"person"; } return rtnStr; } - (NSArray *)iMessage { NSMutableArray *rtnArray = [NSMutableArray array]; ABMultiValueRef instantMessage = ABRecordCopyValue(_recordRef, kABPersonInstantMessageProperty); for (int i = 1; i < ABMultiValueGetCount(instantMessage); i++) { NSString* label = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(instantMessage, i); NSDictionary* content =(__bridge NSDictionary*) ABMultiValueCopyValueAtIndex(instantMessage, i); NSMutableDictionary *imessageInfoDict = [NSMutableDictionary dictionary]; NSString* username = [content valueForKey:(NSString *)kABPersonInstantMessageUsernameKey]; NSString* service = [content valueForKey:(NSString *)kABPersonInstantMessageServiceKey]; DICT_ADD_STR_FOR_KEY(imessageInfoDict, username, @"username"); DICT_ADD_STR_FOR_KEY(imessageInfoDict, service, @"service"); NSDictionary *imessageDict = @{label: imessageInfoDict}; [rtnArray addObject:imessageDict]; } return rtnArray; } -(NSArray *)address { NSMutableArray *rtnArray = [NSMutableArray array]; ABMultiValueRef address = ABRecordCopyValue(_recordRef, kABPersonAddressProperty); long count = ABMultiValueGetCount(address); for(int i = 0; i < count; i++) { NSString* addressLabel = (__bridge NSString*)ABMultiValueCopyLabelAtIndex(address, i); NSDictionary* personaddress =(__bridge NSDictionary*) ABMultiValueCopyValueAtIndex(address, i); NSMutableDictionary *addressInfoDict = [NSMutableDictionary dictionary]; NSString* country = [personaddress valueForKey:(NSString *)kABPersonAddressCountryKey]; NSString* city = [personaddress valueForKey:(NSString *)kABPersonAddressCityKey]; NSString* state = [personaddress valueForKey:(NSString *)kABPersonAddressStateKey]; NSString* street = [personaddress valueForKey:(NSString *)kABPersonAddressStreetKey]; NSString* zip = [personaddress valueForKey:(NSString *)kABPersonAddressZIPKey]; NSString* coutntrycode = [personaddress valueForKey:(NSString *)kABPersonAddressCountryCodeKey]; DICT_ADD_STR_FOR_KEY(addressInfoDict, country, @"country"); DICT_ADD_STR_FOR_KEY(addressInfoDict, city, @"city"); DICT_ADD_STR_FOR_KEY(addressInfoDict, state, @"state"); DICT_ADD_STR_FOR_KEY(addressInfoDict, street, @"street"); DICT_ADD_STR_FOR_KEY(addressInfoDict, zip, @"zip"); DICT_ADD_STR_FOR_KEY(addressInfoDict, coutntrycode, @"coutntrycode"); NSDictionary *addressDict = @{addressLabel: addressInfoDict}; [rtnArray addObject:addressDict]; } return rtnArray; } //- (UIImage *)image //{ // NSData *data = (__bridge NSData*)ABPersonCopyImageData(_recordRef); // return [UIImage imageWithData:data]; //} #pragma mark - #pragma mark - CustomProperty /** * 全名 */ - (NSString *)fullName { return [NSString stringWithFormat:@"%@%@%@", nullStrToEmpty(self.lastName), nullStrToEmpty(self.middlename), nullStrToEmpty(self.firstName)]; } /** * 首字母 */ - (NSString *)firstSpell { return getFirstSpell(self.fullName); } /** * 輸出模型所有信息 */ - (NSString *)description { return [NSString stringWithFormat:@"%@ -- InfoPacket", self.fullName]; } /** * 獲取首字母 */ NSString* getFirstSpell(NSString *fullName) { NSMutableString *ms = [[NSMutableString alloc] initWithString:fullName]; CFStringTransform((__bridge CFMutableStringRef)ms, 0, kCFStringTransformMandarinLatin, NO); CFStringTransform((__bridge CFMutableStringRef)ms, 0, kCFStringTransformStripDiacritics, NO); if (fullName.length > 0) return [[ms substringWithRange:NSMakeRange(0, 1)] lowercaseString]; else return @"#"; } @end