iOS 通訊錄開發(fā)的所有姿勢

通訊錄簡介

通訊錄使用場景:

  1. 電商類的 App轰绵,設置收貨人電話號碼票摇。
  2. 即時通訊類 App亥揖,添加手機聯(lián)系人好友奈梳。

通訊錄獲取方案:

一杈湾、iOS 9 以前的通訊錄框架

  1. AddressBookUI.framework 框架

    1. 提供了聯(lián)系人列表界面、聯(lián)系人詳情界面攘须、添加聯(lián)系人界面等漆撞。
    2. 一般用于選擇聯(lián)系人。
  2. AddressBook.framework 框架

    1. 純 C 語言的 API于宙,僅僅是獲得聯(lián)系人數(shù)據(jù)浮驳。
    2. 沒有提供 UI 界面展示,需要自己搭建聯(lián)系人展示界面捞魁。
    3. 里面的數(shù)據(jù)類型大部分基于 Core Foundation 框架至会,使用起來炒雞復雜。

二谱俭、 iOS 9 以后最新通訊錄框架

  1. ContactsUI.framework 框架奉件。

    • 擁有 AddressBookUI.framework 框架的所有功能,使用起來更加的面向對象昆著。
  2. Contacts.framework 框架县貌。

    • 擁有 AddressBook.framework 框架的所有功能,不再是 C 語言的 API凑懂,使用起來非常簡單煤痕。

iOS 9 以前的通訊錄框架

AddressBookUI

實現(xiàn)步驟

一、創(chuàng)建選擇聯(lián)系人的控制器

// 創(chuàng)建聯(lián)系人選擇控制器    
ABPeoplePickerNavigationController *pvc = [[ABPeoplePickerNavigationController alloc] init];

二征候、設置代理(用來接收用戶選擇的聯(lián)系人信息)

// 設置代理
pvc.peoplePickerDelegate = self;

三杭攻、彈出聯(lián)系人控制器

if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
{
   ABAddressBookRef bookRef = ABAddressBookCreate();
   ABAddressBookRequestAccessWithCompletion(bookRef, ^(bool granted, CFErrorRef error) {
       if (granted)
       {
           NSLog(@"授權成功!");
           [self presentViewController:pvc animated:YES completion:nil];
       }
       else
       {
           NSLog(@"授權失敗!");
       }
   });
}
else if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized)
{
   [self presentViewController:pvc animated:YES completion:nil];
}

四、實現(xiàn)代理方法

// 選擇某個聯(lián)系人時調(diào)用
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person
{
    NSLog(@"選中聯(lián)系人");
    CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
    CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);

    NSString *fir = CFBridgingRelease(firstName);
    NSString *las = CFBridgingRelease(lastName);

    NSLog(@"%@---%@", fir, las);

    ABMultiValueRef multi = ABRecordCopyValue(person, kABPersonPhoneProperty);
    CFIndex count = ABMultiValueGetCount(multi);
    for (int i = 0; i  < count; i++) 
    {
        NSString *label = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(multi, i);
        NSString *phone =(__bridge_transfer NSString *)  ABMultiValueCopyValueAtIndex(multi, i);
        NSLog(@"%@---%@", label, phone);
    }
}

Core Foundation 對象手動管理內(nèi)存疤坝,如果是 Create兆解、Copy、Retain 等字樣創(chuàng)建的對象跑揉,需要手動 CFRelease锅睛。類似 Objective-C 的 MRC。

拓展:__bridge历谍,__bridge_retained__bridge_transfer 三個轉換關鍵字的區(qū)別现拒。

  1. __bridge 只做類型轉換,但是不修改對象(內(nèi)存)管理權望侈;
  2. __bridge_retained(也可以使用CFBridgingRetain)將 Objective-C 的對象轉換為 Core Foundation 的對象印蔬,同時將對象(內(nèi)存)的管理權交給我們,后續(xù)需要使用 CFRelease 或者相關方法來釋放對象脱衙;
  3. __bridge_transfer(也可以使用 CFBridgingRelease )將 Core Foundation 的對象轉換為 Objective-C 的對象侥猬,同時將對象(內(nèi)存)的管理權交給 ARC例驹。

五、在對應的代理方法中獲取聯(lián)系人信息

// 1.選擇聯(lián)系人時使用(不展開詳情)
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person;

// 2.選擇聯(lián)系人某個屬性時調(diào)用(展開詳情)
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier;

// 3.取消選中聯(lián)系人時調(diào)用
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker;

注意:選擇聯(lián)系人的不展開詳情(代理方法1)和展開詳情(代理方法2)的代理方法都寫了的時候退唠,展開詳情的代理方法就不執(zhí)行鹃锈。

AddressBook

一、請求授權

從 iOS 6 開始瞧预,需要得到用戶的授權才能訪問通訊錄屎债,因此在使用之前,需要檢查用戶是否已經(jīng)授權垢油。

// 獲得通訊錄的授權狀態(tài)
ABAddressBookGetAuthorizationStatus()

授權狀態(tài)

  1. 用戶還沒有決定是否授權你的程序進行訪問:kABAuthorizationStatusNotDetermined

  2. iOS 設備上一些許可配置阻止程序與通訊錄數(shù)據(jù)庫進行交互:kABAuthorizationStatusRestricted

  3. 用戶明確的拒絕了你的程序對通訊錄的訪問:kABAuthorizationStatusDenied

  4. 用戶已經(jīng)授權給你的程序對通訊錄進行訪問:kABAuthorizationStatusAuthorized

// 判斷當前的授權狀態(tài)是否是用戶還未選擇的狀態(tài)
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) 
{
   ABAddressBookRef bookRef = ABAddressBookCreate();
   ABAddressBookRequestAccessWithCompletion(bookRef, ^(bool granted, CFErrorRef error) {
       if (granted) 
       {
           NSLog(@"授權成功!");
       }
       else
       {
           NSLog(@"授權失敗!");
       }
   });
}

二盆驹、判斷授權狀態(tài)

如果已授權,則繼續(xù)滩愁;未授權召娜,則提示用戶,并返回惊楼。

// 判斷當前的授權狀態(tài)
if (ABAddressBookGetAuthorizationStatus() != kABAuthorizationStatusAuthorized) 
{
    NSLog(@"您的通訊錄暫未允許訪問,請去設置->隱私里面授權!");
    return;
}

三秸讹、創(chuàng)建通訊錄對象

// 創(chuàng)建通訊錄對象
ABAddressBookRef bookRef = ABAddressBookCreate();

四檀咙、從通信錄對象中, 獲取所有的聯(lián)系人

// 獲取通訊錄中所有的聯(lián)系人
CFArrayRef arrayRef = ABAddressBookCopyArrayOfAllPeople(bookRef);

五、遍歷所有的聯(lián)系人

// 遍歷所有聯(lián)系人
CFIndex count = CFArrayGetCount(arrayRef);
for (int i = 0; i < count; i++) 
{
   ABRecordRef record = CFArrayGetValueAtIndex(arrayRef, i);

   // 獲取姓名
   NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonFirstNameProperty);
   NSString *lastName = (__bridge_transfer NSString *)ABRecordCopyValue(record, kABPersonLastNameProperty);
   NSLog(@"firstName = %@, lastName = %@", firstName, lastName);

   // 獲取電話號碼
   ABMultiValueRef multiValue = ABRecordCopyValue(record, kABPersonPhoneProperty);
   CFIndex count = ABMultiValueGetCount(multiValue);
   for (int i = 0; i < count; i ++) 
   {
       NSString *label = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(multiValue, i);
       NSString *phone = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(multiValue, i);
       NSLog(@"label = %@, phone = %@", label, phone);
   }
   
   CFRelease(multiValue);
}

六璃诀、釋放不再使用的對象

CFRelease(bookRef);
CFRelease(arrayRef);

聯(lián)系人屬性定義

所有的屬性常量值都定義在了 ABPerson.h 頭文件中弧可。

聯(lián)系人屬性包括以下類型:

  1. 簡單屬性:姓、名等
  2. 多重屬性:電話號碼劣欢、電子郵件等
  3. 組合屬性:地址等

注意:使用 ABRecordCopyValue 可以從一條 Person 記錄中獲取到對應的記錄棕诵,但是后續(xù)處理則需要根據(jù)記錄的具體類型加以區(qū)分。

簡單屬性

一個聯(lián)系人就是一個 ABRecordRef凿将,每個聯(lián)系人都有自己的屬性校套,比如名字、電話牧抵、郵件等笛匙。
使用 ABRecordCopyValue 函數(shù)可以從 ABRecordRef 中獲得聯(lián)系人的簡單屬性(例如:一個字符串)。
ABRecordCopyValue 函數(shù)接收 2 個參數(shù)犀变。
第 1 個參數(shù)是 ABRecordRef 實例妹孙。
第 2 個參數(shù)是屬性關鍵字,定義在 ABPerson.h 中获枝。
ABPersonCopyLocalizedPropertyName 函數(shù)可以根據(jù)指定的關鍵字獲取對應的標簽文本蠢正。

獲得所有的聯(lián)系人數(shù)據(jù)

// 獲取所有聯(lián)系人記錄
CFArrayRef array = ABAddressBookCopyArrayOfAllPeople(addressBook);
NSInteger count = CFArrayGetCount(array);

for (NSInteger i = 0; i < count; ++i) {
    // 取出一條記錄
    ABRecordRef person = CFArrayGetValueAtIndex(array, i);
    
    // 取出個人記錄中的詳細信息
    // 名
    CFStringRef firstNameLabel = ABPersonCopyLocalizedPropertyName(kABPersonFirstNameProperty);
    CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
    CFStringRef lastNameLabel = ABPersonCopyLocalizedPropertyName(kABPersonLastNameProperty);
    // 姓
    CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
    
    NSLog(@"%@ %@ - %@ %@", lastNameLabel, lastName, firstNameLabel, firstName);
}

CoreFoundation 與 Foundation之間的橋接

// 1. 獲取通訊錄引用
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);
// 2. 獲取所有聯(lián)系人記錄
NSArray *array = (__bridge NSArray *)(ABAddressBookCopyArrayOfAllPeople(addressBook));
for (NSInteger i = 0; i < array.count; i++) {
    // 取出一條記錄
    ABRecordRef person = (__bridge ABRecordRef)(array[i]);
    // 取出個人記錄中的詳細信息
    NSString *firstNameLabel = (__bridge NSString *)(ABPersonCopyLocalizedPropertyName(kABPersonFirstNameProperty));
    NSString *firstName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonFirstNameProperty));
    NSString *lastNameLabel = (__bridge NSString *)(ABPersonCopyLocalizedPropertyName(kABPersonLastNameProperty));
    NSString *lastName = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonLastNameProperty));
    NSLog(@"%@ %@ - %@ %@", lastNameLabel, lastName, firstNameLabel, firstName);
}
CFRelease(addressBook);

多重屬性

聯(lián)系人的有些屬性值就沒這么簡單,一個屬性可能會包含多個值
比如郵箱省店,分為工作郵箱嚣崭、住宅郵箱笨触、其他郵箱等
比如電話,分為工作電話有鹿、住宅電話旭旭、其他電話等
如果是復雜屬性,那么 ABRecordCopyValue 函數(shù)返回的就是 ABMultiValueRef 類型的數(shù)據(jù)葱跋,例如郵箱或者電話

// 取電話號碼
ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);
// 取記錄數(shù)量
NSInteger phoneCount = ABMultiValueGetCount(phones);
// 遍歷所有的電話號碼
for (NSInteger i = 0; i < phoneCount; i++) 
{

}

獲取復雜屬性的方法

// 電話標簽
CFStringRef phoneLabel = ABMultiValueCopyLabelAtIndex(phones, i);
// 本地化電話標簽
CFStringRef phoneLocalLabel = ABAddressBookCopyLocalizedLabel(phoneLabel);
// 電話號碼
CFStringRef phoneNumber = ABMultiValueCopyValueAtIndex(phones, i);

添加聯(lián)系人的步驟

添加聯(lián)系人的步驟:

  1. 通過 ABPersonCreate 函數(shù)創(chuàng)建一個新的聯(lián)系人(返回 ABRecordRef)持寄。
  2. 通過 ABRecordSetValue 函數(shù)設置聯(lián)系人的屬性。
  3. 通過 ABAddressBookAddRecord 函數(shù)將聯(lián)系人添加到通訊錄數(shù)據(jù)庫中娱俺。
  4. 通過 ABAddressBookSave 函數(shù)保存剛才所作的修改稍味。

可以通過 ABAddressBookHasUnsavedChanges 函數(shù)判斷是否有未保存的修改
當決定是否更改通訊錄數(shù)據(jù)庫后,你可以分別使用 AbAddressBookSaveABAddressBookRevert 方式來保存或放棄更改 荠卷。

添加群組的步驟

添加群組的步驟大體和添加聯(lián)系人一致:

  1. 通過 ABPersonCreate 函數(shù)創(chuàng)建一個新的組模庐。(返回 ABRecordRef
  2. 通過 ABRecordSetValue 函數(shù)設置組名。
  3. 通過 ABAddressBookAddRecord 函數(shù)將組添加到通訊錄數(shù)據(jù)庫中油宜。
  4. 通過 ABAddressBookSave 函數(shù)保存剛才所作的修改掂碱。

操作聯(lián)系人的頭像

想操作聯(lián)系人的頭像,有以下函數(shù)
BPersonHasImageData
判斷通訊錄中的聯(lián)系人是否有圖片

ABPersonCopyImageData
取得圖片數(shù)據(jù)(假如有的話)

ABPersonSetImageData
設置聯(lián)系人的圖片數(shù)據(jù)

通訊錄的修改回調(diào)

// 創(chuàng)建通訊錄
self.addressBook = ABAddressBookCreate();  
// 注冊通知  
ABAddressBookRegisterExternalChangeCallback(self.addressBook, _addressBookChange, nil);            
// 處理收到通知的 Action
void _addressBookChange(ABAddressBookRef addressBook, CFDictionaryRef info, void *context)
{
}
- (void)dealloc
{
    // 注銷通知
    ABAddressBookUnregisterExternalChangeCallback(self.addressBook, _addressBookChange, nil);
    // 釋放對象
    CFRelease(self.addressBook);
}

iOS 9 以后的通訊錄新框架

iOS 9 之前操作通訊錄還是比較麻煩的慎冤,iOS 9 以后蘋果推出了全新的通訊錄框架疼燥,使用起來更加的面向對象。

CNContactUI

實現(xiàn)步驟

一蚁堤、創(chuàng)建選擇聯(lián)系人的控制器

// 創(chuàng)建聯(lián)系人選擇控制器    
CNMutableContact *contact = [[CNMutableContact alloc] init];
CNLabeledValue *labelValue = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMobile
ontact.phoneNumbers = @[labelValue];                                                                     value:[CNPhoneNumber phoneNumberWithStringValue:phoneNum]];
CNContactViewController *contactController = [CNContactViewController viewControllerForNewContact:contact];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:contactController];

二醉者、設置代理(用來接收用戶選擇的聯(lián)系人信息)

// 設置代理
contactController.delegate = self;

三、彈出聯(lián)系人控制器

[controller presentViewController:nav animated:YES completion:nil];

四披诗、實現(xiàn)代理方法

// 選擇某個聯(lián)系人時調(diào)用
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty
{
    CNContact *contact = contactProperty.contact;
    NSString *name = [CNContactFormatter stringFromContact:contact style:CNContactFormatterStyleFullName];
    CNPhoneNumber *phoneValue= contactProperty.value;
    NSString *phoneNumber = phoneValue.stringValue;
    NSLog(@"%@--%@",name, phoneNumber);
}

五撬即、在對應的代理方法中獲取聯(lián)系人信息

// 1.選擇聯(lián)系人時使用(不展開詳情)
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact;

// 2.選擇聯(lián)系人某個屬性時調(diào)用(展開詳情)
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty;

// 3.取消選中聯(lián)系人時調(diào)用
- (void)contactPickerDidCancel:(CNContactPickerViewController *)picker;

注意:與 AddressBookUI 一樣,選擇聯(lián)系人的不展開詳情(代理方法1)和展開詳情(代理方法2)的代理方法都寫了的時候呈队,展開詳情的代理方法就不執(zhí)行剥槐。

CNContact

實現(xiàn)步驟

一、請求授權

// 獲得通訊錄的授權狀態(tài)
CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts]

授權狀態(tài)

  1. 用戶還沒有決定是否授權你的程序進行訪問:CNAuthorizationStatusNotDetermined

  2. iOS 設備上一些許可配置阻止程序與通訊錄數(shù)據(jù)庫進行交互:CNAuthorizationStatusRestricted

  3. 用戶明確的拒絕了你的程序對通訊錄的訪問:CNAuthorizationStatusDenied

  4. 用戶已經(jīng)授權給你的程序對通訊錄進行訪問:CNAuthorizationStatusAuthorized

// 判斷當前的授權狀態(tài)是否是用戶還未選擇的狀態(tài)
if (status == CNAuthorizationStatusNotDetermined)
{
    CNContactStore *store = [CNContactStore new];
    [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) {
        if (granted) 
        {
            NSLog(@"授權成功!");
        }
        else
        {
            NSLog(@"授權失敗!");
        }
    }];
}

二掂咒、判斷授權狀態(tài)

如果已授權才沧,則繼續(xù);未授權绍刮,則提示用戶温圆,并返回。

// 判斷當前的授權狀態(tài)
if (status != CNAuthorizationStatusAuthorized) 
{
    NSLog(@"您的通訊錄暫未允許訪問孩革,請去設置->隱私里面授權!");
    return;
}

三岁歉、創(chuàng)建通訊錄對象

// 創(chuàng)建通訊錄對象
CNContactStore *contactStore = [CNContactStore new];

四、設置訪問的屬性 Key,每個 Key 對應一個屬性锅移,iOS 9 新增熔掺,如果沒有設置,訪問該屬性就會崩潰非剃。

// 姓名前綴
CNContactNamePrefixKey     
// 名                 
CNContactGivenNameKey                       
// 中間名
CNContactMiddleNameKey  
// 姓                   
CNContactFamilyNameKey            
// 婚前姓         
CNContactPreviousFamilyNameKey
// 姓名后綴
CNContactNameSuffixKey   
// 昵稱                   
CNContactNicknameKey                        
// 公司
CNContactOrganizationNameKey                
// 部門
CNContactDepartmentNameKey                  
// 職位
CNContactJobTitleKey                        
// 名字拼音或音標
CNContactPhoneticGivenNameKey
// 中間名拼音或音標              
CNContactPhoneticMiddleNameKey
// 姓拼音或音標
CNContactPhoneticFamilyNameKey  
// 公司拼音或音標            
CNContactPhoneticOrganizationNameKey      
// 生日  
CNContactBirthdayKey   
// 農(nóng)歷                    
CNContactNonGregorianBirthdayKey    
// 備注        
CNContactNoteKey                            
// 圖片
CNContactImageDataKey                       
// 縮略圖
CNContactThumbnailImageDataKey              
// 圖片是否允許訪問
CNContactImageDataAvailableKey              
// 類型
CNContactTypeKey                            
// 號碼
CNContactPhoneNumbersKey                    
// 電子郵件
CNContactEmailAddressesKey                  
// 地址
CNContactPostalAddressesKey                 
// 日期
CNContactDatesKey   
// URL                        
CNContactUrlAddressesKey                    
// 關聯(lián)人
CNContactRelationsKey                       
// 社交
CNContactSocialProfilesKey                  
// 即時通訊
CNContactInstantMessageAddressesKey         
NSArray *keys = @[CNContactPhoneNumbersKey,CNContactGivenNameKey];

五置逻、從通信錄對象中, 獲取所有的聯(lián)系人,并遍歷

// 獲取通訊錄中所有的聯(lián)系人
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];
   
[contactStore enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
    // 獲取姓名
    NSString *firstName = contact.familyName;
    NSString *lastName = contact.givenName;
      
    NSLog(@"%@--%@",firstName,lastName);
    
    // 獲取電話號碼
      
    for (CNLabeledValue *labeledValue in contact.phoneNumbers)
    {
         CNPhoneNumber *phoneValue = labeledValue.value;
         NSString *phoneNumber = phoneValue.stringValue;
         NSString *label = [CNLabeledValue localizedStringForLabel:labeledValue.label];
         NSLog(@"%@--%@",label,phoneNumber);
    }

}];

通訊錄的修改回調(diào)

// 注冊通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_contactStoreDidChange) name:CNContactStoreDidChangeNotification object:nil]            
// 處理收到通知的 Action
- (void)_contactStoreDidChange
{
}
- (void)dealloc
{   
    // 注銷通知
    [[NSNotificationCenter defaultCenter] removeObserver:self name:CNContactStoreDidChangeNotification object:nil];
}

當 App 活躍(前臺+后臺活動期間)的時候备绽,當通訊錄修改的時候券坞,會收到通知
當 App 不活躍的時候(掛起的時候),App 收不到通知肺素;而是恨锚,當 App 到前臺的時候收到延遲的通知。

LJContactManager

介紹

LJContanctManager 是我寫的一款操作通訊錄的類庫倍靡,iOS 9 之前使用的是 AddressBook 和 AddressBookUI 系統(tǒng)庫猴伶,iOS 9 之后使用蘋果新推出的 Contacts 和 ContactsUI 框架。

安裝

CocoaPods

  1. 在 Podfile 中添加 pod 'LJContactManager'塌西。
  2. 執(zhí)行 pod installpod update他挎。
  3. 導入 <LJContactManager.h>。

手動安裝

  1. 下載 LJContactManager 文件夾內(nèi)的所有內(nèi)容捡需。
  2. 將 LJContactManager 內(nèi)的源文件添加(拖放)到你的工程雇盖。
  3. 導入 LJContactManager.h

使用

主要提供以下的方法:

  • 選擇聯(lián)系人
/**
 選擇聯(lián)系人

 @param controller 控制器
 @param completcion 回調(diào)
 */
- (void)selectContactAtController:(UIViewController *)controller
                      complection:(void (^)(NSString *name, NSString *phone))completcion;
  • 創(chuàng)建新聯(lián)系人
/**
 創(chuàng)建新聯(lián)系人

 @param phoneNum 手機號
 @param controller 當前 Controller
 */
- (void)createNewContactWithPhoneNum:(NSString *)phoneNum controller:(UIViewController *)controller;
  • 添加到現(xiàn)有聯(lián)系人
/**
 添加到現(xiàn)有聯(lián)系人

 @param phoneNum 手機號
 @param controller 當前 Controller
 */
- (void)addToExistingContactsWithPhoneNum:(NSString *)phoneNum controller:(UIViewController *)controller;
  • 獲取聯(lián)系人列表(未分組的通訊錄)
/**
 獲取聯(lián)系人列表(未分組的通訊錄)
 
 @param completcion 回調(diào)
 */
- (void)accessContactsComplection:(void (^)(BOOL succeed, NSArray <LJPerson *> *contacts))completcion;
  • 獲取聯(lián)系人列表(已分組的通訊錄)
/**
 獲取聯(lián)系人列表(已分組的通訊錄)

 @param completcion 回調(diào)
 */
- (void)accessSectionContactsComplection:(void (^)(BOOL succeed, NSArray <LJSectionPerson *> *contacts, NSArray <NSString *> *keys))completcion;
  • 通訊錄變更回調(diào)(未分組的通訊錄)
/**
 通訊錄變更回調(diào)(未分組的通訊錄)
 */
@property (nonatomic, copy) void (^contactsChangeHanlder) (BOOL succeed, NSArray <LJPerson *> *newContacts);
  • 通訊錄變更回調(diào)(已分組的通訊錄)
/**
 通訊錄變更回調(diào)(已分組的通訊錄)
 */
@property (nonatomic, copy) void (^sectionContactsHanlder) (BOOL succeed, NSArray <LJSectionPerson *> *newSectionContacts, NSArray <NSString *> *keys);

最后

由于筆者水平有限栖忠,文中如果有錯誤的地方汞窗,或者有更好的方法贡避,還望大神指出。
附上本文的所有 demo 下載鏈接闪朱,【GitHub】薛匪。
如果你看完后覺得對你有所幫助捐川,還望在 GitHub 上點個 star。贈人玫瑰逸尖,手有余香古沥。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市娇跟,隨后出現(xiàn)的幾起案子岩齿,更是在濱河造成了極大的恐慌,老刑警劉巖苞俘,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盹沈,死亡現(xiàn)場離奇詭異,居然都是意外死亡吃谣,警方通過查閱死者的電腦和手機乞封,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門做裙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肃晚,你說我怎么就攤上這事锚贱。” “怎么了关串?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵拧廊,是天一觀的道長。 經(jīng)常有香客問我悍缠,道長卦绣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任飞蚓,我火速辦了婚禮滤港,結果婚禮上,老公的妹妹穿的比我還像新娘趴拧。我一直安慰自己溅漾,他們只是感情好,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布著榴。 她就那樣靜靜地躺著添履,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脑又。 梳的紋絲不亂的頭發(fā)上暮胧,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機與錄音问麸,去河邊找鬼往衷。 笑死,一個胖子當著我的面吹牛严卖,可吹牛的內(nèi)容都是我干的席舍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼哮笆,長吁一口氣:“原來是場噩夢啊……” “哼来颤!你這毒婦竟也來了?” 一聲冷哼從身側響起稠肘,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤福铅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后项阴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體本讥,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了拷沸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片色查。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖撞芍,靈堂內(nèi)的尸體忽然破棺而出秧了,到底是詐尸還是另有隱情,我是刑警寧澤序无,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布验毡,位于F島的核電站,受9級特大地震影響帝嗡,放射性物質(zhì)發(fā)生泄漏晶通。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一哟玷、第九天 我趴在偏房一處隱蔽的房頂上張望狮辽。 院中可真熱鬧,春花似錦巢寡、人聲如沸喉脖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽树叽。三九已至,卻和暖如春谦絮,著一層夾襖步出監(jiān)牢的瞬間题诵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工层皱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留仇轻,地道東北人。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓奶甘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親祭椰。 傳聞我的和親對象是個殘疾皇子臭家,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 這幾天內(nèi)钉赁,發(fā)生的事情,讓我迸發(fā)的詞語是:整體觀携茂,系統(tǒng)觀你踩。像前些日子,一個文件放在文件夾的時候就可以打開,單獨拿出的...
    橋墩閱讀 1,354評論 0 2
  • 講一講我喜歡的一個動漫人物带膜。 他叫宇智波鼬吩谦,來自《NARUTO》。喜歡的原因也很簡單膝藕,他是“哥哥”這一...
    金閃閃閱讀 402評論 4 0