// // RAContactManager.m // ContactDemo // // Created by Jack on 2018/12/24. // Copyright © 2018 USAI. All rights reserved. // #import "RAContactManager.h" #import #import "CNContact+RAContact.h" @implementation RAContactManager + (instancetype)defaultManager { static RAContactManager *manager; static dispatch_once_t token; dispatch_once(&token, ^{ manager = [[RAContactManager alloc] init]; }); return manager; } #pragma mark - Authorization - (void)requestAuthorization:(void(^)(BOOL granted))completion { if ([CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] == CNAuthorizationStatusAuthorized) { if (completion) { completion(YES); } } else { CNContactStore *store = [[CNContactStore alloc] init]; [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { if (completion) { completion(granted); } }]; } } #pragma mark - Get - (void)searchContactWithPredicate:(NSPredicate *)predicate completionHandler:(void(^)(NSArray *contacts, NSError *error))completion { // 创建联系人仓库 CNContactStore *store = [[CNContactStore alloc] init]; // 创建联系人的请求对象 // keys决定能获取联系人哪些信息,例:姓名,电话,头像等 NSArray *fetchKeys = @[ CNContactIdentifierKey, CNContactGivenNameKey, CNContactFamilyNameKey, CNContactMiddleNameKey, CNContactImageDataKey, CNContactOrganizationNameKey, CNContactDepartmentNameKey, CNContactJobTitleKey, CNContactPhoneNumbersKey, CNContactEmailAddressesKey, CNContactPostalAddressesKey, CNContactSocialProfilesKey, CNContactUrlAddressesKey, CNContactNoteKey ]; CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:fetchKeys]; request.sortOrder = CNContactSortOrderFamilyName; request.predicate = predicate; // 请求联系人 NSError *error = nil; NSMutableArray *contacts = [NSMutableArray array]; [store enumerateContactsWithFetchRequest:request error:&error usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { [contacts addObject:contact]; }]; if (error) { contacts = nil; } if (completion) { completion([contacts copy], error); } } - (void)fetchAllContactCompletionHandler:(void(^)(NSArray *contacts, NSError *error))completion { [self searchContactWithPredicate:nil completionHandler:completion]; } - (void)searchContactByKeyword:(NSString *)keyword completionHandler:(void(^)(NSArray *contacts, NSError *error))completion { if (keyword) { [self searchContactWithPredicate:nil completionHandler:^(NSArray *contacts, NSError *error) { if (error) { if (completion) { completion(nil, error); } } else { NSMutableArray *keywordContacts = [NSMutableArray array]; for (CNContact *c in contacts) { if ([c ra_containsKeyWord:keyword]) { [keywordContacts addObject:c]; } } if (completion) { completion(keywordContacts, nil); } } }]; } else { [self searchContactWithPredicate:nil completionHandler:completion]; } } - (void)searchContactByName:(NSString *)name completionHandler:(void(^)(NSArray *contacts, NSError *error))completion { [self searchContactWithPredicate:[CNContact predicateForContactsMatchingName:name] completionHandler:completion]; } #pragma mark - Add - (void)insertContact:(CNMutableContact *)contact completionHandler:(void(^)(BOOL result,NSError *error))completion { if (contact) { CNContactStore *store = [[CNContactStore alloc] init]; CNSaveRequest *request = [[CNSaveRequest alloc] init]; [request addContact:contact toContainerWithIdentifier:nil]; NSError *err; [store executeSaveRequest:request error:&err]; if (completion) { completion(err == nil, err); } } else { if (completion) { completion(NO, [NSError errorWithDomain:NSCocoaErrorDomain code:404 userInfo:@{@"msg":@"contact is nil"}]); } } } #pragma mark - Remove - (void)removeContact:(CNContact *)contact completionHandler:(void(^)(BOOL result,NSError *error))completion { if (contact) { if (contact.identifier != nil) { CNContactStore *store = [[CNContactStore alloc] init]; CNSaveRequest *request = [[CNSaveRequest alloc] init]; [request deleteContact:contact.mutableCopy]; NSError *err; [store executeSaveRequest:request error:&err]; if (completion) { completion(err == nil, err); } } else { if (completion) { completion(NO, [NSError errorWithDomain:NSCocoaErrorDomain code:404 userInfo:@{@"msg":@"contact's identifier is nil"}]); } } } else { if (completion) { completion(NO, [NSError errorWithDomain:NSCocoaErrorDomain code:404 userInfo:@{@"msg":@"contact is nil"}]); } } } #pragma mark - Modify - (void)updateContact:(CNMutableContact *)contact completionHandler:(void(^)(BOOL result,NSError *error))completion { if (contact) { if (contact.identifier != nil) { CNContactStore *store = [[CNContactStore alloc] init]; CNSaveRequest *request = [[CNSaveRequest alloc] init]; [request updateContact:contact]; NSError *err; [store executeSaveRequest:request error:&err]; if (completion) { completion(err == nil, err); } } else { if (completion) { completion(NO, [NSError errorWithDomain:NSCocoaErrorDomain code:404 userInfo:@{@"msg":@"contact's identifier is nil"}]); } } } else { if (completion) { completion(NO, [NSError errorWithDomain:NSCocoaErrorDomain code:404 userInfo:@{@"msg":@"contact is nil"}]); } } } #pragma mark - Utils - (NSString *)getFirstLetterFromString:(NSString *)aString { if (aString) { NSMutableString *str = [NSMutableString stringWithString:aString]; //带声调的拼音 CFStringTransform((CFMutableStringRef)str,NULL, kCFStringTransformMandarinLatin,NO); NSLog(@"%@",str); //不带声调的拼音 CFStringTransform((CFMutableStringRef)str,NULL, kCFStringTransformStripDiacritics,NO); //转化为大写拼音 NSString *strPinYin = [str capitalizedString]; NSString *firstString = [strPinYin substringToIndex:1]; //判断姓名首位是否为大写字母 NSString * regexA = @"^[A-Z]$"; NSPredicate *predA = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regexA]; //获取并返回首字母 return [predA evaluateWithObject:firstString] ? firstString : @"#"; } else{ return @"#"; } } - (void)addContact:(CNContact *)contact toGroupDictionary:(NSMutableDictionary *> *)dic { if (contact && dic) { NSString *firstLetter = [self getFirstLetterFromString:contact.familyName]; if (!dic[firstLetter]) { dic[firstLetter] = [NSMutableArray array]; } [dic[firstLetter] addObject:contact]; } } - (void)sortGroupedContactsByFamilyNameFirstLetter:(NSArray *)contacts completion:(void(^)(NSArray *sortedKeys, NSDictionary *> *contactGroup))completion { if (contacts && contacts.count > 0) { NSMutableDictionary *> *dic = [NSMutableDictionary dictionary]; for (CNContact *c in contacts) { [self addContact:c toGroupDictionary:dic]; } // 对Group排序 [dic enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSMutableArray * _Nonnull obj, BOOL * _Nonnull stop) { [obj sortUsingComparator:^NSComparisonResult(CNContact * _Nonnull obj1, CNContact * _Nonnull obj2) { return [obj1.familyName localizedCompare:obj2.familyName]; }]; }]; NSArray *sortedKeys = [dic.allKeys sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { return [obj1 localizedCompare:obj2]; }]; if (completion) { completion(sortedKeys, dic); } } else { if (completion) { completion(nil, nil); } } } @end