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
@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,这个后期会研究一下,并发表出来。