苹果在iOS9的SDK中废除了AddressBookUI.framework的一些功能(是不是这个库都废除了,有待验证),具体和保存联系人相关的几个系统界面如下:
联系人选择:AddressBookUI/ABPeoplePickerNavigationController.h
联系人详情:AddressBookUI/ABPersonViewController.h
未知联系人:AddressBookUI/ABUnknownPersonViewController.h
新建联系人:AddressBookUI/ABNewPersonViewController.h
新的SDK中使用
联系人选择:ContactsUI/CNContactPickerViewController.h
联系人详情、新建联系人、未知联系人:ContactsUI/CNContactViewController.h(使用不同方法创建,下面会说)
下面的链接是官方的ppt,讲的很详细,不过是swift版本
http://devstreaming.apple.com/videos/wwdc/2015/223rmo6dv9hxh/223/223_introducing_the_contacts_framework_for_ios_and_os_x.pdf
我要分享的是OC的实现,下面是我的实例。

一.需求
我的老项目里面的需求和微信的效果是一样的(下图为微信截图),这里先吐槽下,这个功能实现起来要区分ios7(6),ios8,ios9

 
二.思路
保存新联系人非常简单使用系统的新建联系人页,把需要保存的对象封装传入,剩下的交给系统处理就好;
保存现有联系人可能就费点心思了,有两种方式一个是使用未知联系人页面处理(我的客户比较NB,必须按需求100%实现),另一种是先跳转到选择页面中获取一个现有联系人的对象,再跳转到新建好友页面(把该对象传入),之后的事情交给系统处理(这个困扰了我很久,后来受到微信的启发,才想出来这个野路子)

三.实现(模拟器无法保存,请用真机调试),demo:   Contact4iOS9.zip (38 K) 下载次数:36 
导入头文件
#import <ContactsUI/CNContactViewController.h>
#import <ContactsUI/CNContactPickerViewController.h>

保存新联系人实现
- (void)saveNewContact{
    //1.创建Contact对象,必须是可变的
    CNMutableContact *contact = [[CNMutableContact alloc] init];
    //2.为contact赋值,这块比较恶心,很混乱,setValue4Contact中会给出常用值的对应关系
    [self setValue4Contact:contact existContect:NO];
    //3.创建新建好友页面
    CNContactViewController *controller = [CNContactViewController viewControllerForNewContact:contact];
    //代理内容根据自己需要实现
    controller.delegate = self;
    //4.跳转
    UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:controller];
    [self presentViewController:navigation animated:YES completion:^{
        
    }];
    
}

保存现有联系人实现
//保存现有联系人实现
- (void)saveExistContact{
    //1.跳转到联系人选择页面,注意这里没有使用UINavigationController
    CNContactPickerViewController *controller = [[CNContactPickerViewController alloc] init];
    controller.delegate = self;
    [self presentViewController:controller animated:YES completion:^{
        
    }];
}

//2.实现点选的代理,其他代理方法根据自己需求实现
- (void)contactPicker:(CNContactPickerViewController *)picker didSelectContact:(CNContact *)contact{
    [picker dismissViewControllerAnimated:YES completion:^{
        //3.copy一份可写的Contact对象,不要尝试alloc一类,mutableCopy独此一家
        CNMutableContact *c = [contact mutableCopy];
        //4.为contact赋值
        [self setValue4Contact:c existContect:YES];
        //5.跳转到新建联系人页面
        CNContactViewController *controller = [CNContactViewController viewControllerForNewContact:c];
        controller.delegate = self;
        UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:controller];
        [self presentViewController:navigation animated:YES completion:^{
        }];
    }];
}

对应关系
//设置要保存的contact对象
- (void)setValue4Contact:(CNMutableContact *)contact existContect:(BOOL)exist{
    if (!exist) {
        //名字和头像
        contact.nickname = @"oriccheng";
        //        UIImage *logo = [UIImage imageNamed:@"..."];
        //        NSData *dataRef = UIImagePNGRepresentation(logo);
        //        contact.imageData = dataRef;
    }
    //电话,每一个CNLabeledValue都是有讲究的,如何批评,可以在头文件里面查找,这里给出几个常用的,别的我也不愿意去研究
    CNLabeledValue *phoneNumber = [CNLabeledValue labeledValueWithLabel:CNLabelPhoneNumberMobile value:[CNPhoneNumber phoneNumberWithStringValue:@"18888888888"]];
    if (!exist) {
        contact.phoneNumbers = @[phoneNumber];
    }
    //现有联系人情况
    else{
        if ([contact.phoneNumbers count] >0) {
            NSMutableArray *phoneNumbers = [[NSMutableArray alloc] initWithArray:contact.phoneNumbers];
            [phoneNumbers addObject:phoneNumber];
            contact.phoneNumbers = phoneNumbers;
        }else{
            contact.phoneNumbers = @[phoneNumber];
        }
    }
    
    //网址:CNLabeledValue *url = [CNLabeledValue labeledValueWithLabel:@"" value:@""];
    //邮箱:CNLabeledValue *mail = [CNLabeledValue labeledValueWithLabel:CNLabelWork value:self.poiData4Save.mail];
    
    //特别说一个地址,PostalAddress对应的才是地址
    CNMutablePostalAddress *address = [[CNMutablePostalAddress alloc] init];
    address.state = @"辽宁省";
    address.city = @"沈阳市";
    address.postalCode = @"111111";
    //外国人好像都不强调区的概念,所以和具体地址拼到一起
    address.street = @"沈河区惠工街10号";
    //生成的上面地址的CNLabeledValue,其中可以设置类型CNLabelWork等等
    CNLabeledValue *addressLabel = [CNLabeledValue labeledValueWithLabel:CNLabelWork value:address];
    if (!exist) {
        contact.postalAddresses = @[addressLabel];
    }else{
        if ([contact.postalAddresses count] >0) {
            NSMutableArray *addresses = [[NSMutableArray alloc] initWithArray:contact.postalAddresses];
            [addresses addObject:addressLabel];
            contact.postalAddresses = addresses;
        }else{
            contact.postalAddresses = @[addressLabel];
        }
    }
}

四.一个未解决bug:
联系人编辑页面点击拍照,无法拍照,黑屏,我看微信也是这样的,还在找出问题的原因
  
 
五.总结
新的方法整体比之前更加面向对象了,不像之前这copy那copy的,好用了一些,但是联系人的属性实在太多了,代码写起来很慢,另外苹果也提供了新的联系人读写操作的方法,用起来也同样比之前的更好理解,主要类是CNSaveRequest和CNContactStore,用起来和FMDB很像,这里就不举例了,最后吐槽下苹果吧,现在iOS系统升级给老程序带来了很多的工作,我在做的就是一个三年前的老项目,本身就很庞大复杂,还不断在修改需求、加功能,真是被苹果玩吐血啊。

六.附赠我遇到的iOS9必改内容
1.国际化判断
2.高级的定位功能
3.https加密问题
4.老程序使用Default.png方式设置欢迎页面,无法获取屏幕高度
5.联系人api更换

iOS9联系人保存详解相关推荐

  1. Android联系人Contacts详解

    1.获取联系人详细信息 在(一)中我们只是获取了联系人的ID和NAME,但是这是远远不够的,怎么样获取其他的值呢? public void fetchContactInformation() {Str ...

  2. 帆软报表填报自定义提交-后台数据解析保存详解

    帆软报表填报前期步骤按api或者百度就可以完成,今天我这里着重讲解自定义提交(访问web后台服务进行提交). 填报提交有两种方式: 1)内置SQL:没什么难度,按教程来就行. 2)自定义提交:对应后台 ...

  3. iOS9画中画开发详解

    最近写一个基于AVPlayer的iPad视频播放器,可手势调节音量和进度,完成之后,想到iOS9的新特性,心血来潮想搞PIP,毕竟未来的视频类App,不支持PIP,都不好意思拿出来用了...后面链接上 ...

  4. java base64转文件_JAVA将Base64转为文件并保存详解

    public static void base64ToFile(String base64, String fileName, String savePath) { File file = null; ...

  5. 【OpenCV 4开发详解】保存和读取XML和YMAL文件

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  6. 【OpenCV 4开发详解】图像与视频的保存

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  7. 使用pickle保存机器学习模型详解及实战(pickle、joblib)

    使用pickle保存机器学习模型详解及实战 pickle模块实现了用于序列化和反序列化Python对象结构的二进制协议. "Pickling"是将Python对象层次结构转换为字节 ...

  8. onenote怎么同步到电脑_详解onenote保存与同步④:本地笔记奇葩的丢失经历

    (此文介绍的是我遇到过的,极其奇葩的,丢失onenote本地笔记的惨痛经历.不论是否具有普遍性,对进一步理解缓存还是很有帮助的.大家若有其他丢失经历,可以交流.) 对于onenote本地笔记本而言,由 ...

  9. adb logcat 保存_adb命令——日志命令详解——全部输出到桌面: adb logcat c:\users\del\desktop\log.txt...

    adb logcat 一.在cmd窗口查看手机的Log日志 有时候我们在手机程序上的日志要在其他地方调试,然后要看里面的Log日志.在cmd窗口中输入如下命令: //格式1:打印默认日志数据 adb ...

最新文章

  1. STL_Hash_map
  2. ORACLE将表中的数据恢复到某一个时间点
  3. 手把手教你部署一个最小化的 Kubernetes 集群
  4. 视频编码中的RC(rate control)是什么?码率控制 CBR (Constant Bit Rate)、VBR (Variable Bit Rate)
  5. 我与微软的不解之缘 - 我的Insider Dev Tour 2019讲师之旅
  6. 如果 AI 和算法无罪,那么谁在杀死穷人?
  7. 优先级调度算法动态优先级_与优先级调度有关的问题及其解决方案
  8. jpa 生成uuid的主键_JPA注解主键生成策略-UUID
  9. Modelsim的安装教程
  10. 很好的--张量(Tensor)的技术以及它在不同场景中的应用--转载贪心科技
  11. 软件架构风格——4+1视图、5大传统架构风格及其它风格
  12. Android微信页面缓存清理,安卓用户如何彻底清理微信大量缓存?4招让你彻底解决内存烦恼...
  13. 如何用hb制作一个html网页,HTML网页制作基础
  14. 唱作俱佳,腾讯AI艾灵领唱中国新儿歌
  15. 转贴--爱的最高境界
  16. 推荐一个非常好的IOS编程技巧网站
  17. c位边上还有什么位_λ(c位旁边二个位置叫什么)
  18. cordova 插件cordova-plugin-crosswalk-webview - Android 集成crosswalk浏览器内核
  19. 容器类存储表格数据(12)
  20. Dataset之ApolloScape :ApolloScape Scene Parsing数据集的简介、下载、使用方法之详细攻略

热门文章

  1. Unity3D 控制物体移动且自动旋转
  2. PC微信多开-完整傻瓜版
  3. 【pytest】pytest报告插件开源作品
  4. android八核手机,为什么都八核了手机还是卡?谈智能手机的流畅性
  5. 射线p0-p1相对于Y轴负向顺时针旋转角度
  6. 欢迎来到无处遁形的广告世界
  7. 高德地图——定位,POI搜索
  8. 第三章 ArcGIS Pro创建 python 脚本工具(五)
  9. 怎么在手机上取消双重认证_手机怎么连到电视上?
  10. CAD复制,怎样位移复制CAD图形?