1、現在的很多應用程序中都會設計到手機系統通訊錄的問題,下面就簡單介紹一下iOS系統通訊錄的
2、iOS9之前的系統通訊錄有2個框架,分別是AddressBookUI/AddressBookUI.h // 系統帶UI通訊錄, AddressBook/AddressBook.h // 系統通訊錄,需要自己手動搭建頁面,
3、 AddressBookUI/AddressBookUI.h // 系統帶UI通訊錄,不用自己搭建頁面,直接調用系統的就可以了,
ABPeoplePickerNavigationController *vc = [[ABPeoplePickerNavigationController alloc] init];
vc.peoplePickerDelegate = self;
[self presentViewController:vc animated:YES completion:nil];
遵守代理ABPeoplePickerNavigationControllerDelegate,並實現代理方法:
// ios7
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
NSLog(@"111111");
[peoplePicker dismissViewControllerAnimated:YES completion:nil];
}
// 在iOS7中選中一個聯繫人就會調用
// 返回一個BOOL值,NO代表不會進入到下一層(詳情),YES代表會進入到下一層
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{
return NO;
}
// ios8選中一個聯繫人就會調用 實現這個方法之後,控制器不會進入到下一層(詳情),直接dismiss
//- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person{
// NSLog(@"2222");
//}
// ios8選中某一個聯繫人的某一個屬性時就會調用
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
NSLog(@"%@,%d,@%d",person,property,identifier);
}
這樣的話,就能夠直接利用系統的通訊錄界面進行操作了,但是有一點就是,不能在界面上操作需求。
4、獲取聯繫人。
AddressBook/AddressBook.h // 系統通訊錄,需要自己手動搭建頁面,這個框架只能夠通過手動拿到聯繫人數據,然後自己搭建界面展示數據,並可以進行其他的需求操作。
(1)爲了更方便的展示數據,首先創建person模型類:PeopleModel
#import <UIKit/UIKit.h>
@interface PeopleModel : NSObject
@property (nonatomic, copy) NSString *name; // 姓名
@property (nonatomic, copy) NSString *email; // 郵箱
@property (nonatomic, copy) NSString *tellPhone; // 電話
@property (nonatomic, strong) UIImage *iconImage; // 聯繫人頭像
@property (nonatomic, assign) NSInteger sectionNumber; // section標題(用於按某一個屬性排序,比如按照name排序)
@end
從通訊錄中獲取所有的聯繫人,並轉換成person模型類,
(2)首先創建數據源,數據源一定要初始化,很多時候忘記初始化數據源會導致看不到數據,
@property (nonatomic ,retain) NSMutableArray *peoplePhoneData; // 用來存儲聯繫人(分組)
// self.peoplePhoneData = [NSMutableArray array]; // 記得初始化數據源(這裏就不用懶加載了)
(3)取得通訊錄授權:程序在第一次使用的時候,會請求用戶的授權,如果用戶同意了,就加載數據,拒絕了,就給提示。如果不是第一次使用通訊錄,就不再提示授權的提示框,但程序同樣要走到下面的請求函數,這時系統會自動識別授權狀態,granted=1,就是已經授權的,granted=0就是拒絕授權或者其他的,總之只有同意授權纔可以拿數據的。
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(nil, error);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
NSLog(@"granted==%d",granted);
if (granted) {
NSLog(@"授權成功!");
[self getUpAddBookViewPersonDataWithAddBook:addressBook];
} else {
NSLog(@"授權失敗!");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"授權失敗" message:@"請在設置中打開訪問權限" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
[alert show];
}
});
獲取授權狀態也可以用ABAddressBookGetAuthorizationStatus()獲取授權狀態,
kABAuthorizationStatusNotDetermined = 0, // 還沒有決定是否授權(就是在第一次提示授權的時候)
kABAuthorizationStatusRestricted, // 有其他限制通訊錄授權的狀態
kABAuthorizationStatusDenied, // 拒絕授權
kABAuthorizationStatusAuthorized // 同意授權
(4)獲取所有聯繫人並按照拼音排序(效果就是系統通訊錄的排序效果),都是c語言的語法,與oc轉化的時候是通過__bridge(橋接)來互相轉換的
// 獲取所有聯繫人並存儲
- (void)getUpAddBookViewPersonDataWithAddBook:(ABAddressBookRef)addressBook
{
// 獲取所有聯繫人並存儲
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook);
CFIndex peolpeCount = ABAddressBookGetPersonCount(addressBook); // 獲取聯繫人個數
NSMutableArray *peopleArray = [NSMutableArray array]; // 用來存儲聯繫人模型
// 獲取聯繫人信息(將聯繫人轉模型)
for (NSInteger i = 0; i < peolpeCount; i++)
{
PeopleModel *model = [[PeopleModel alloc] init];
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i); // 獲取某一個聯繫人
CFStringRef firstName = ABRecordCopyValue(person, kABPersonFirstNameProperty);
CFStringRef lastName = ABRecordCopyValue(person, kABPersonLastNameProperty);
CFStringRef fullName = ABRecordCopyCompositeName(person);
// 取出個人記錄中的詳細信息
// 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);
// 讀取name
NSString *firstNameStr = (__bridge NSString *)firstName;
NSString *lastNameStr = (__bridge NSString *)lastName;
NSString *fullNameStr = (__bridge NSString *)fullName;
if ( fullNameStr.length != 0) {
firstNameStr = fullNameStr;
} else if (lastNameStr.length!=0) {
firstNameStr = [NSString stringWithFormat:@"%@ %@",firstNameStr,lastNameStr];
}
model.name = firstNameStr;
// 讀取郵箱
ABMultiValueRef email = ABRecordCopyValue(person, kABPersonEmailProperty);
NSInteger emailCount = ABMultiValueGetCount(email);
for (NSInteger i = 0; i < emailCount; i++) {
model.email = (__bridge NSString *)ABMultiValueCopyValueAtIndex(email, i);
}
// 讀取電話
ABMultiValueRef tellPhone = ABRecordCopyValue(person, kABPersonPhoneProperty);
for (NSInteger i = 0; i < ABMultiValueGetCount(tellPhone); i++) {
model.tellPhone = (__bridge NSString *)ABMultiValueCopyValueAtIndex(tellPhone, i);
}
// for (NSInteger i = 0; i < ABMultiValueGetCount(tellPhone); i++) {
//// 獲取複雜屬性的方法
// // 電話標籤
// CFStringRef phoneLabel = ABMultiValueCopyLabelAtIndex(tellPhone, i);
// // 本地化電話標籤
// CFStringRef phoneLocalLabel = ABAddressBookCopyLocalizedLabel(phoneLabel);
// // 電話號碼
// CFStringRef phoneNumber = ABMultiValueCopyValueAtIndex(tellPhone, i);
// }
// 讀取聯繫人頭像
NSData *iconData = (__bridge NSData *)ABPersonCopyImageData(person);
model.iconImage = [UIImage imageWithData:iconData];
[peopleArray addObject:model];
if (firstName) {
CFRelease(firstName);
}
if (lastName) {
CFRelease(lastName);
}
if (fullName) {
CFRelease(fullName);
}
CFRelease(email);
CFRelease(tellPhone);
}
// 排序
UILocalizedIndexedCollation *theCollation = [UILocalizedIndexedCollation currentCollation];
for (PeopleModel *model in peopleArray) {
NSInteger sect = [theCollation sectionForObject:model
collationStringSelector:@selector(name)]; // 根據模型的name字斷排序
model.sectionNumber = sect;
}
NSInteger highSection = [[theCollation sectionTitles] count];
NSMutableArray *sectionArrays = [NSMutableArray arrayWithCapacity:highSection];
for (int i=0; i<=highSection; i++) {
NSMutableArray *sectionArray = [NSMutableArray arrayWithCapacity:1];
[sectionArrays addObject:sectionArray];
}
for (PeopleModel *model in peopleArray) {
[(NSMutableArray *)[sectionArrays objectAtIndex:model.sectionNumber] addObject:model];
}
// 排好序的聯繫人加入數組中
for (NSMutableArray *sectionArray in sectionArrays) {
int count = 0; // 統計name爲nil的個數
for (PeopleModel *model in sectionArray) {
if (model.name.length==0) {
count++;
}
}
NSArray *sortedSection = [NSArray array];
// NSArray *sortedSection = [theCollation sortedArrayFromArray:sectionArray collationStringSelector:@selector(name)];
if (count >= 2) { // 有2個以上name爲nil,
sortedSection = [NSArray arrayWithArray:sectionArray];
} else {
sortedSection = [theCollation sortedArrayFromArray:sectionArray collationStringSelector:@selector(name)];
}
[self.peoplePhoneData addObject:sortedSection];
}
[self.tableView reloadData];
}
在iOS的通訊錄中的聯繫人的名字是有好幾個的(firstName,lastName,fullName),所有按照需求來操作,並且手機號,郵箱都是有多個的,所有這些需求就需要按照設計需求來做了。
(5)索引實現。
// 索引序列
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
tableView.sectionIndexColor = [UIColor redColor];
tableView.sectionIndexBackgroundColor=[UIColor clearColor];
NSArray * array=[[NSArray arrayWithObject:@"★"] arrayByAddingObjectsFromArray:[[UILocalizedIndexedCollation currentCollation] sectionIndexTitles]];
return [[NSArray arrayWithObject:UITableViewIndexSearch] arrayByAddingObjectsFromArray:array];
}
(6)section title
- (NSString )tableView:(UITableView )tableView titleForHeaderInSection:(NSInteger)section
{
NSString *title = [self.peoplePhoneData[section] count] ? [[[UILocalizedIndexedCollation currentCollation] sectionTitles] objectAtIndex:section]:nil;
return title;
}
5、修改聯繫人
// 修改聯繫人
- (void)updateRecod{
// 1. 拿到通訊錄
ABAddressBookRef book = ABAddressBookCreateWithOptions(NULL, NULL);
// 獲取通訊錄所有人
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(book);
// 拿到通訊錄中的某一個聯繫人
ABRecordRef people = CFArrayGetValueAtIndex(allPeople, 0);
// 修改聯繫人信息
ABRecordSetValue(people, kABPersonLastNameProperty, @"Li", NULL);
// 保存通訊錄
ABAddressBookSave(book, NULL);
// ABPersonHasImageData(people); // 判斷通訊錄中的聯繫人是否有圖片
// ABPersonSetImageData(people, <#CFDataRef imageData#>, <#CFErrorRef *error#>); // 設置聯繫人的圖片數據
// ABAddressBookRemoveRecord(<#ABAddressBookRef addressBook#>, <#ABRecordRef record#>, <#CFErrorRef *error#>) // 刪除某一個聯繫人
// ABAddressBookRevert(<#ABAddressBookRef addressBook#>) // 放棄更改信息
// ABAddressBookHasUnsavedChanges(<#ABAddressBookRef addressBook#>) // 函數判斷是否有未保存的修改
}
5、添加新的聯繫人
// 添加聯繫人
- (void)creadRecod{
// 1. 創建聯繫人
ABRecordRef people = ABPersonCreate();
// 2. 設置聯繫人信息
ABRecordSetValue(people, kABPersonLastNameProperty, @"san", NULL);
ABRecordSetValue(people, kABPersonFirstNameProperty, @"zhang", NULL);
// 創建電話號碼
ABMultiValueRef phones = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(phones, @"123456789", kABPersonPhoneMainLabel, NULL);
ABMultiValueAddValueAndLabel(phones, @"888888", kABPersonPhoneHomeFAXLabel, NULL);
ABRecordSetValue(people, kABPersonPhoneProperty, phones, NULL);
// 3. 拿到通訊錄
ABAddressBookRef book = ABAddressBookCreateWithOptions(NULL, NULL);
// 4. 將聯繫人添加到通訊錄中
ABAddressBookAddRecord(book, people, NULL);
// 5. 保存通訊錄
ABAddressBookSave(book, NULL);
}
6、聯繫人的操作基本上就那麼多了,有一些屬性值是沒有涉及到的,但是基本的操作方法都差不多。但是在iOS9之後,系統的通訊錄框架改成了 ContactsUI/ContactsUI.h,這個後期會研究一下,並發表出來。