iOS 通讯录编程【总结】
第一大块儿:读取通讯录
1、iOS 6以上系统,争取获取用户允许:
-(id)init{
self = [super init];
[self createdABHandle];
bool isAuthorized = [self isAuthorizedAddressBook];
if (!isAuthorized) {
ABAddressBookRequestAccessWithCompletion(_addressBook, ^(bool granted, CFErrorRef error){
if (granted){
//[self createAddressBuddyData];
}
});
}
return self;
}
看看isAuthorizedAddressBook的内容:
- (BOOL)isAuthorizedAddressBook {
if (SYSTEM_VERSION <= 6.0){
return YES;
}
//
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status == kABAuthorizationStatusNotDetermined) {
return NO;
}
else if(status == kABAuthorizationStatusAuthorized) {
return YES;
}
else if (status == kABAuthorizationStatusDenied) {
return NO;
}
return NO;
}
2、获取联系人。获取联系人分组
ABAddressBookRef addressBook =ABAddressBookCreate();
NSArray* allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople (addressBook));
NSArray* allGroups = CFBridgingRelease(ABAddressBookCopyArrayOfAllGroups(addressBook));
for (id person in (NSArray *) allPeople)
[self logContact:person];
for (id group in (NSArray *) allGroups)
[self logGroup:group];
CFRelease(addressBook);
3、联系人字段获取技巧:
● 获取个人或群体完整名称。
比如:NSString* name = (NSString*)ABRecordCopyCompositeName(record);
● 获取联系人ID ABRecordID recId = ABRecordGetRecordID(record);
● 获取电话。邮箱列表,生日等,多键值的方法 比如:ABMultiValueRef phoneNumbersArr = ABRecordCopyValue(record, kABPersonPhoneProperty);
● 获取联系人分组名称 CFStringRef name = ABRecordCopyValue(group,kABGroupNameProperty);
● 获取联系人分组ID ABRecordID recId = ABRecordGetRecordID(group);
在获取多值的属性时候须要注意:获取地址的时候,多键值有嵌套。
代码例如以下:
NSArray *allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); int i;
for (i = 0; i < [allPeople count]; i++) {
ABRecordRef record = [allPeople objectAtIndex:i]; ABMutableMultiValueRef multiValue = ABRecordCopyValue(record, kABPersonAddressProperty);
for(CFIndex i=0;i<ABMultiValueGetCount(multiValue);i++)
{
NSString* HomeLabel=(NSString*)ABMultiValueCopyLabelAtInde x(multiValue, i);
if([HomeLabel isEqualTo:@"_$!<Home>!$_"])
{
CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(multiValueArr, i);
NSString* street =CFBridgingRelease( CFDictionaryGetValue(dict, kABPersonAddressStreetKey));
NSString* city =CFBridgingRelease( CFDictionaryGetValue(dict, kABPersonAddressCityKey));
NSString* country =CFBridgingRelease(CFDictionaryGetValue(dict, kABPersonAddressCountryKey));
CFRelease(dict); NSString *syntheticAddress = [NSString stringWithFormat:@"%@, %@, %@"
,(street?street:@"")
,(city?city:@"")
,(country?country:@"")];
}
不能直接调用ABMultiValueCopyValueAtIndex,然后强转成NSString*
4、删除联系人或者群组
ABAddressBookRemoveRecord(addressBook, people, NULL);
ABAddressBookSave(addressBook, NULL);
第二大块儿:写入通讯录
/*
更新联系人,比方phoneTypePairArr为空,那么程序把一个空的ABMultiValueRef写入addressBook,达到删除的效果。
*/
-(BOOL) updateToAB:(ABRecordRef)person withContact:(RCSContact*)contact{
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);
// 保存到联系人对象中,假设属性为nil,则表示要删除
//lastname
NSString* lastName = contact.lastName.length? contact.lastName:nil;
ABRecordSetValue(person, kABPersonLastNameProperty, (__bridge CFStringRef)lastName, NULL); //firstName
NSString* firstName = [contact.firstName length]? contact.firstName:nil;
ABRecordSetValue(person, kABPersonFirstNameProperty, (__bridge CFStringRef)firstName, NULL); //birthday
if ([contact.birthday length]) {
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
[inputFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"]];
[inputFormatter setDateFormat:@"yyyy-MM-dd"];
NSDate* inputDate = [inputFormatter dateFromString:contact.birthday];
ABRecordSetValue(person, kABPersonBirthdayProperty, (__bridge CFDateRef)inputDate, NULL);
}else{
ABRecordSetValue(person, kABPersonBirthdayProperty, NULL, NULL);
} //company name
NSString* companyName = [contact.companyName length]?contact.companyName:nil;
ABRecordSetValue(person, kABPersonOrganizationProperty, (__bridge CFStringRef)companyName, NULL); //company duty
NSString* companyDuty = [contact.companyDuty length]?contact.companyDuty:nil;
ABRecordSetValue(person, kABPersonJobTitleProperty, (__bridge CFStringRef)companyDuty, NULL);
// ABMultiValueRef相似是Objective-C中的NSMutableDictionary
ABMultiValueRef mv = ABMultiValueCreateMutable(kABMultiStringPropertyType);
NSArray* tmpArr = [NSArray arrayWithArray:contact.phoneTypePairArr];
for (PhoneTypePair* p in tmpArr) {
if ([p.content length]==0) {
continue;
}
NSString* label = [_typeDic_ForWrite objectForKey:p.type];
ABMultiValueIdentifier mi = ABMultiValueAddValueAndLabel(mv, (__bridge CFStringRef)p.content, (__bridge CFStringRef)label, &mi);
}
ABRecordSetValue(person, kABPersonPhoneProperty, mv, NULL);
if (mv) { CFRelease(mv);}
//设置邮箱
ABMutableMultiValueRef emailCFArray = ABMultiValueCreateMutable(kABStringPropertyType);
tmpArr = [NSArray arrayWithArray:contact.eMailArr];
for (PhoneTypePair* p in tmpArr) {
//邮件的话
if ([p.content length]==0) {
continue;
}
NSString* label = [_typeDic_ForWrite objectForKey:p.type];
ABMultiValueAddValueAndLabel(emailCFArray,(__bridge CFStringRef)(p.content),(__bridge CFStringRef)label,NULL);
}
ABRecordSetValue(person, kABPersonEmailProperty, emailCFArray, NULL);
if(emailCFArray){CFRelease(emailCFArray);} //设置地址
ABMutableMultiValueRef multiAddress = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
tmpArr = [NSArray arrayWithArray:contact.addressArr];
for (PhoneTypePair* p in tmpArr) {
//地址的话
if ([p.content length]==0) {
continue;
}
NSMutableDictionary *addressDictionary = [[NSMutableDictionary alloc] init];
[addressDictionary setObject:[p.content mutableCopy] forKey:(NSString *)kABPersonAddressStreetKey];
[addressDictionary setObject:@"" forKey:(NSString *)kABPersonAddressCityKey];
[addressDictionary setObject:@"" forKey:(NSString *)kABPersonAddressStateKey];
[addressDictionary setObject:@"" forKey:(NSString *)kABPersonAddressZIPKey];
[addressDictionary setObject:@"" forKey:(NSString *)kABPersonAddressCountryCodeKey];
//set label
NSString* label = [_typeDic_ForWrite objectForKey:p.type];
ABMultiValueAddValueAndLabel(multiAddress, CFBridgingRetain(addressDictionary), (__bridge CFStringRef)label, NULL);
}
ABRecordSetValue(person, kABPersonAddressProperty, multiAddress, NULL);
if (multiAddress) {CFRelease(multiAddress);} // 设置头像属性
ABPersonRemoveImageData(person, NULL);
ABAddressBookAddRecord(addressBook, person, nil); //设置头像
NSData *data = UIImagePNGRepresentation(contact.portrait);
ABAddressBookSave(addressBook, NULL);
if ([data length]==0) {
ABPersonRemoveImageData(person, NULL);
}else{
CFDataRef cfData = CFDataCreate(NULL, [data bytes], [data length]);
ABPersonSetImageData(person, cfData, nil);
} // 将新建的联系人加入到通讯录中,保存通讯录
ABAddressBookAddRecord(addressBook, person, NULL);
bool isSucess = ABAddressBookSave(addressBook, NULL);
NSLog (@"加入一个人到数据库成功[%d]",isSucess);
// 释放通讯录对象的引用
if (addressBook) {
CFRelease(addressBook);
}
return isSucess;
比如:第35,47,61行,都是採用拷贝数组。防止多线程下读、写数组。导致enumed error
第三大块儿:监听通讯录变更
client代码须要这么实现:
/*
移除注冊函数
*/
-(void)dealloc{
ABAddressBookUnregisterExternalChangeCallback(_addressBook, ContactsChangeCallback, nil);
}
/*
注冊回调函数
*/
- (id)init {
self = [super init];
[self addressBookHandle];
ABAddressBookRegisterExternalChangeCallback(_addressBook, ContactsChangeCallback, nil); return self;
}
/*
回调函数,实现自己的逻辑。 */
void ContactsChangeCallback (ABAddressBookRef addressBook,
CFDictionaryRef info,
void *context){ NSLog(@"ContactsChangeCallback");
}
_addressBook是通讯录句柄。尽管有监听的接口,可是參数info总是空的。
另外:当本APP编辑系统通讯录时候。不会收到通知;通知可能有多个,这时候能够採取:“仅仅处理第一个通知,淹没后面的通知。
”。也能够採取信号量机制,对变更通知一个个在线程中处理。防止界面卡顿。
另外:在加入新的联系人的时候,使用ABNewPersonViewController。特别注意,一定要处理好它的代理:
// Called when the user selects Save or Cancel. If the new person was saved, person will be
// a valid person that was saved into the Address Book. Otherwise, person will be NULL.
// It is up to the delegate to dismiss the view controller.
- (void)newPersonViewController:(ABNewPersonViewController *)newPersonView didCompleteWithNewPerson:(ABRecordRef)person;
处理不好,造成APP崩溃。
我的处理是这种:
[self.navigationController popToViewController:self animated:YES];
监听规则:
当App活跃(前台+后台保活期间)的时候,当通讯录改动的时候,会收到通知
当App不活跃的时候(挂起的时候)。App收不到通知;而是,当App到前台的时候收到延迟的通知。
生成vcard
/*************************************************
* @brief 获取通讯录联系列表的vcard
* @param 无
* @retun 无
*************************************************/
- (void)getLocalAddressBookvCard { CFArrayRef persons = ABAddressBookCopyArrayOfAllPeople(_addressBook);
CFDataRef vcards = (CFDataRef)ABPersonCreateVCardRepresentationWithPeople(persons); NSString *vcardString = [[NSString alloc] initWithData:(__bridge NSData *)vcards encoding:NSUTF8StringEncoding]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *folderPath = [paths objectAtIndex:0];
NSString *filePath = [folderPath stringByAppendingPathComponent:@"contacts.vcf"];
NSLog(@"path = %@",filePath); [vcardString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
}
生成到document文件夹下的contacts.vcf文件
还能够用以下的办法。更适合生成单个crad
+(NSData*)exportContactsToVcard:(NSArray*)contacts
{
NSMutableArray *people = [NSMutableArray arrayWithCapacity:contacts.count];
ABAddressBookRef ab = ABAddressBookCreate();
for (Contact *contact in contacts)
{
ABRecordRef person = ABAddressBookGetPersonWithRecordID(ab,contact.contactId);
[people addObject:(__bridge id)person];
}
NSData *vCard = (__bridge NSData*)ABPersonCreateVCardRepresentationWithPeople((__bridge CFArrayRef) people);
return vCard;
}
从vcard生成person
ABAddressBookRef book = ABAddressBookCreate();
ABRecordRef defaultSource = ABAddressBookCopyDefaultSource(book);
CFArrayRef vCardPeople = ABPersonCreatePeopleInSourceWithVCardRepresentation(defaultSource, vCardData);
for (CFIndex index = 0; index < CFArrayGetCount(vCardPeople); index++) {
ABRecordRef person = CFArrayGetValueAtIndex(vCardPeople, index);
ABAddressBookAddRecord(book, person, NULL);
}
CFRelease(vCardPeople);
CFRelease(defaultSource);
ABAddressBookSave(book, NULL);
CFRelease(book);
iOS 通讯录编程【总结】的更多相关文章
- iOS通讯录相关知识-浅析
本文来自于:贞娃儿的博客 http://blog.sina.com.cn/zhenwawaer 在开发一些应用中,我们如果需要iPhone设备中的通讯录信息.或者,需要开发通讯录相关的一些功能.那 ...
- iOS网络编程模型
iOS网络编程层次结构也分为三层: Cocoa层:NSURL,Bonjour,Game Kit,WebKit Core Foundation层:基于 C 的 CFNetwork 和 CFNetServ ...
- IOS网络编程——第三方类库
IOS网络编程——第三方类库 目录 概述 ASIHttpRequest AFNetworking 其他 概述 ASIHttpRequest AFNetworking 其他
- iOS 6编程Cookbook(影印版)
<iOS 6编程Cookbook(影印版)> 基本信息 原书名:iOS 6 Programming Cookbook 作者: Vandad Nahavandipoor 出版社:东南大学出版 ...
- iOS 并行编程:NSOperation Queues
1 简介 1.1 功能 Operation Queue也是IOS的一种并行编程技术,类似Dispatch Queue可以帮助用户管理多线程.但是Operation Queue将任务封装在 ...
- IOS网络编程:HTTP
IOS网络编程:HTTP HTTP定义了一种在服务器和客户端之间传递数据的途径. URL定义了一种唯一标示资源在网络中位置的途径. REQUESTS 和 RESPONSES: 客户端先建立一个TCP连 ...
- 深入浅出-iOS函数式编程的实现 && 响应式编程概念
简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 配图 ...
- [HMLY]11.iOS函数式编程的实现&&响应式编程概念
简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 作为一 ...
- iOS网络编程笔记——Socket编程
一.什么是Socket通信: Socket是网络上的两个程序,通过一个双向的通信连接,实现数据的交换.这个双向连路的一端称为socket.socket通常用来实现客户方和服务方的连接.socket是T ...
随机推荐
- python网络爬虫数据中的三种数据解析方式
一.正则解析 常用正则表达式回顾: 单字符: . : 除换行以外所有字符 [] :[aoe] [a-w] 匹配集合中任意一个字符 \d :数字 [0-9] \D : 非数字 \w :数字.字母.下划线 ...
- java 重载父类报错 Remove '@override' annotation解决办法
Remove '@override' annotation解决办法 最近刚刚配置了新机器,将原来的代码放在eclipse上执行,总会出现Remove '@override' annotati ...
- Github提交本地版本是遇到的问题
问题如下:*** Please tell me who you are. Run git config --global user.email "you@example.com" ...
- Unity通过指定摄像机截屏
简介 介于照抄网上之前的截图教程,然后在实际应用过程中出现了一些小小的问题,修正了一下下,特此分享一下 PS:代码在后面 原理 原理很简单,就是将一个相机的内容渲染到一个贴图上,然后将贴图保存为图片 ...
- cocos2dx实现单机版三国杀(一)
首先需要一个UI交互类 GameUI -layer 一个游戏驱动类,负责游戏逻辑的循环 暂时定为GameScene- scene GameScene obj 调用update 更新游戏,addch ...
- Product Device Lot
Product是指产品: 这个Product可以在不同的设备类型上生产, 同一类型的设备也可能硬件有差异,所以会有相对应的Device(Recipe): 同一Product(或同一Device)由于数 ...
- html5——动画案例(大海)
太阳的发散效果主要是利用transform: scale(1.3),将物体变大 <!DOCTYPE html> <html lang="en"> <h ...
- JS——模拟百度搜索
注意事项: 1.for循环移除子节点时,其长度是变化的 2.在文档流中,input.img.p等标签与其他标签有3px的距离,利用左浮动,可以消除3px距离 3.背景图片定位时,第一个值是x轴方向的值 ...
- IP访问频率限制不能用数组循环插入多个限制条件原因分析及解决方案
14.IP频率限制不能用数组循环插入多个限制条件原因分析及解决方案: define("RATE_LIMITING_ARR", array('3' => 3, '6' => ...
- C# 获得固定年月日
/// <summary> /// 获得固定年月日,时和分不固定 : 2019-01-01 00:00:00 /// </summary> /// <returns> ...