第一大块儿:读取通讯录

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);

第二大块儿:写入通讯录

注意。在写入通讯录的时候,有些contact的phone,email,address是多个的。鉴于多线程的安全因素,在使用的时候都是获取拷贝。
/*更新联系人,比方phoneTypePairArr为空,那么程序把一个空的ABMultiValueRef写入addressBook,达到删除的效果。*/
-(BOOL) updateToAB:(ABRecordRef)person withContact:(RCSContact*)contact{ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, nil);// 保存到联系人对象中,假设属性为nil,则表示要删除//lastnameNSString* 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 通讯录编程【总结】相关推荐

  1. iOS DLNA编程

    iOS DLNA编程 近期实现了iOS下的DLNA,发现ios下的DLNA编程资料很少,其实DLNA文档还好 (28m) ,但是真的确定要看文档自己去实现么? 下面先介绍一下DLNA的基本概念,已经有 ...

  2. iOS网络编程-iCloud键值数据存储编程实例

    iCloud键值数据存储设计 iCloud键值数据存储编程实例,画面中有两个开关控件,左图是设备1点击"设置iCloud数据"按钮,将控件状态保存到iCloud服务器.右图是设备2 ...

  3. iOS代码编程规范 根据项目经验汇总

    带出几十位从零开始学iOS的实习生或试用期的开发人员后,觉得真的是千人千面,每个人写的代码都风格迥异,如果没有一个文档规范,每次都和新人进行口头的说教,大概自己是不用敲代码了,所以吃了亏了就开始编写i ...

  4. iOS网络编程开发—HTTP协议

    iOS网络编程开发-HTTP协议 说明:apache tomcat服务器必须占用8080端口 一.URL 1.基本介绍 URL的全称是Uniform Resource Locator(统一资源定位符) ...

  5. iOS网络编程-配置iCloud-图文解说

    配置iCloud 开发iCloud应用一方面需要准备真实的iOS设备,另一方面还需要有iOS开发者账号, 使 用iOS开发者账号登录到iOS开发中心的配置门户网站(iOS Provisioning P ...

  6. 一步一步学习iOS 5编程(第三版)-PDF中文版-正式发布!

    目前,这是第一本介绍iOS 5.x 和 Xcode 4.4 的中文版书籍,尤其适合于iOS 编程开发初学者.本教程由 EntLib.com 团队编写.如有任何技术问题,欢迎留言. 电子版 – PDF ...

  7. iOS网络编程开发-数据加密

    iOS网络编程开发-数据加密 一.简单说明 1.说明 在开发应用的时候,数据的安全性至关重要,而仅仅用POST请求提交用户的隐私数据,还是不能完全解决安全问题. 如:可以利用软件(比如Charles) ...

  8. 《iOS网络编程与云端应用最佳实践》微博转发送书了!

    <iOS网络编程与云端应用最佳实践>微博转发送书了! 新浪微博地址:http://weibo.com/2078101705/zy15U4a5D,转发本条微博即有机会获得<iOS网络编 ...

  9. 转发网络《iOS网络编程与云端应用最佳实践》微博转发送书了

    在写这篇文章之前,xxx已经写过了几篇关于改转发网络主题的文章,想要了解的朋友可以去翻一下之前的文章 <iOS网络编程与云端应用最佳实践>微博转发送书了! 新浪微博地址:http://we ...

  10. iOS 通讯录备份、恢复

            和相册 备份一样,公司产品备份功能有通讯录备份 功能,自然也有通讯录恢复了.iOS通讯录相关操作,iOS对通讯录的操作离不开的框架: #import <AddressBook/A ...

最新文章

  1. ​“好师父”如何破解大学生就业难题
  2. java正则表达式替换指定字符串_笔记_正则表达式替换字符串中特定范围内的字符。...
  3. fft重叠帧_关于FFT实时频谱的几个基本概念 | 科创仪表局
  4. SQL:数据表给定字段的多行记录的合并
  5. php redis与me m,Redis(十) —— 为php增加redis扩展
  6. mcrypt拓展_【PHP】Mcrypt 扩展模块安装及使用
  7. Java基础学习总结(21)——常用正则表达式列表
  8. 2018-2019-1 20165318 20165326 实验五 通讯协议设计
  9. HTTP/2之服务器推送(Server Push)最佳实践
  10. 起点文学网ViewState解码分析后的结果研究
  11. QTDesigner简介
  12. 计算机管理磁盘分区,一分钟搞定电脑磁盘分区,再也不求人!
  13. wxpython各种基本控件_wxpython 基本的控件
  14. esp8266调用心知天气
  15. 劳动与社会保障法-作业
  16. linux kvm切换器,PS2系列KVM切换器
  17. ArcGIS_栅格数据归一化
  18. Android绘制颜色渐变图形
  19. python播放mp3文件
  20. 计算机科学与技术的班徽设计,地球科学与技术学院 2017级班级班徽创意设计大赛获奖公示...

热门文章

  1. Transact-SQL管理与开发实例精粹
  2. windowsf进程管理器中进程解释
  3. mmap函数_Linux中的mmap映射 [二]
  4. 数字盲打怎么练_数字键盘区的功能及指法技巧
  5. mysql怎么进行删除操作_利用PHP怎么对MySQL数据库进行删除操作
  6. Android报错:java.lang.ClassCastException: com.github.mikephil.charting.charts.PieChart cannot be cast
  7. Android【报错】java.lang.ClassCastException: android.widget.TextView cannot be cast to android.widget.Bu
  8. elipse开发android 如何查看报错信息
  9. Android修改了sdk里面的apk编译push进机器不生效问题
  10. python入门基础2 if语句 while循环 for循环