iOS 修改通讯录联系人地址(address)崩溃原因分析
目前项目中需要对iOS系统通讯录进行读取,修改操作。在进行对地址修改的时候,出现了一个奇怪现象:
● 如果contact没有address字段(或者一个全新的contact),对它的address进行修改是可以成功的,
● 如果这个人有过address字段,此时对它就行修改就崩溃。控制台打出:
*** -[CFString release]: message sent to deallocated instance 0x81d26f0
这应该是一个僵尸对象,重复释放某一个对象。首先我对修改通讯录的代码进行检查,但是没发现问题,下面是代码
- //设置地址
- ABMutableMultiValueRef multiAddress = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
- for (PhoneTypePair* p in contact.addressArr) {
- //内容判断空
- if ([p.content length]==0) {
- continue;
- }
- NSMutableDictionary *addressDictionary = [[NSMutableDictionary alloc] init];
- //把地址只写入street字段中
- [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];
- //将字典放入多值对象中
- if ([p.type isEqualToString:kAddressType_Work]) {
- ABMultiValueAddValueAndLabel(multiAddress, CFBridgingRetain(addressDictionary), kABWorkLabel, NULL);
- }else if ([p.type isEqualToString:kAddressType_Home]){
- ABMultiValueAddValueAndLabel(multiAddress, CFBridgingRetain(addressDictionary), kABHomeLabel, NULL);
- }else{
- ABMultiValueAddValueAndLabel(multiAddress, CFBridgingRetain(addressDictionary), kABOtherLabel, NULL);
- }
- }
- ABRecordSetValue(person, kABPersonAddressProperty, multiAddress, NULL);
- ABAddressBookAddRecord(addressBook, person, nil);
- ABAddressBookSave(addressBook, NULL);
- if (multiAddress) {
- CFRelease(multiAddress);
- }
程序崩溃在 ABAddressBookSave(addressBook, NULL); 百思不得其解,google上查阅了很多资料,看看是不是“多值”的对象使用错了,还是代码顺序的问题。都没有结果。
后来,我想起来了Instruments这个工具,可以查看僵尸对象。立即起profile。结果如下:
Zombie的地方是ABCMultiValueDestroy。但是,我注意到了AddressBookEngine的getAddress:函数。突然我恍然大悟,应该读取的时候CF和OC对象转换的问题。随机,我打开网址,转向ARC说明
__bridge只做类型转换,但是不修改对象(内存)管理权;
__bridge_retained(也可以使用CFBridgingRetain)将Objective-C的对象转换为Core Foundation的对象,同时将对象(内存)的管理权交给我们,后续需要使用CFRelease或者相关方法来释放对象;
__bridge_transfer(也可以使用CFBridgingRelease)将Core Foundation的对象转换为Objective-C的对象,同时将对象(内存)的管理权交给ARC。
那么问题,应该就在读取address的地方了:看代码
- /**
- * 获取地址
- *
- * @param recordRef 通讯录单个联系人引用
- *
- * @return 地址
- */
- -(NSDictionary*) getAddress:(ABRecordRef)recordRef{
- //1.判定
- if (recordRef == nil) {
- return nil;
- }
- NSMutableArray *addressHome = [[NSMutableArray alloc]init];
- NSMutableArray *addressWork = [[NSMutableArray alloc]init];
- NSMutableArray *other = [[NSMutableArray alloc]init];
- //2.创建字典,获取多键值列表
- NSMutableDictionary *multiValueDic = [[NSMutableDictionary alloc] initWithCapacity:1];
- ABMultiValueRef multiValueArr = ABRecordCopyValue(recordRef, kABPersonAddressProperty);
- //3.将多值,封装到字典中。
- int count = multiValueArr ? ABMultiValueGetCount(multiValueArr) : 0 ;
- if (count > 0) {
- count = (count <= kMaxAddressNumber?count:kMaxAddressNumber);
- for(int i = 0; i < count; i++) {
- @autoreleasepool {
- //lable
- //注意桥接,将CF对象转成OC对象。ARC下,自动释放OC对象:参考http://blog.csdn.net/hherima/article/details/16356577
- NSString* label = CFBridgingRelease(ABMultiValueCopyLabelAtIndex(multiValueArr,i));
- //value
- 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:@"")];
- if (label == nil || [label isEqualToString:@"_$!<Home>!$_"]){
- [addressHome addObject:syntheticAddress];
- }
- else if([label isEqualToString:@"_$!<Work>!$_"]){
- [addressWork addObject:syntheticAddress];
- }
- else{
- [other addObject:syntheticAddress];
- }
- }
- }
- [multiValueDic setObject:addressHome forKey:@(EAdressBookType_AddressHome)];
- [multiValueDic setObject:addressWork forKey:@(EAdressBookType_AddressWork)];
- [multiValueDic setObject:other forKey:@(EAdressBookType_AddressOther)];
- }
- //4.释放CF对象
- if (NULL != multiValueArr) {
- CFRelease(multiValueArr);
- multiValueArr = NULL;
- }
- return multiValueDic;
- }
在找到具体问题之前,我做了一个假设。如果从一开始就此函数return掉,如果不崩溃,说明就是后续代码的问题。果不其然!
问题就出在:
CFRelease(dict);
由于我已经使用了CFBridgingRelease,说明不需要在releasedict这个对象了。主要是上面的代码,是从网上copy的。没有改
http://blog.csdn.net/hherima/article/details/41594273
iOS 修改通讯录联系人地址(address)崩溃原因分析的更多相关文章
- CSipIm断网重连崩溃原因分析
断网重连之后的操作流程 拨打电话 ->调用SipService.makeCallOptions(),先重启一遍SipService保证PjSipService的各参数正常,尤其是create参数 ...
- 【转】iOS应用崩溃日志分析
作为一名应用开发者,你是否有过如下经历? 为确保你的应用正确无误,在将其提交到应用商店之前,你必定进行了大量的测试工作.它在你的设备上也运行得很好,但是,上了应用商店后,还是有用户抱怨会闪退 ! ...
- iOS应用崩溃日志分析
转自raywenderlich 作为一名应用开发者,你是否有过如下经历? 为确保你的应用正确无误,在将其提交到应用商店之前,你必定进行了大量的测试工作.它在你的设备上也运行得很好,但是,上了应 ...
- iOS有关通讯录操作
一.首先获取用户通讯录授权信息. 在AppDelegate中导入#import <AddressBook/AddressBook.h>框架,在下列方法中获取授权信息. - (BOOL)ap ...
- ios 获取通讯录的所有信息
iOS获取通讯录全部信息 ABAddressBookRef addressBook = ABAddressBookCreate(); CFArrayRef results = ABAddressBoo ...
- ios读取通讯录信息
ios读取通讯录信息 (2012-05-22 14:07:11) 标签: ios读取通讯录 it iphone如许app读取通讯录信息,读取通讯录信息时需要加载AddressBookUI 和Add ...
- iOS应用崩溃日志分析 iOS应用崩溃日志揭秘
转自:http://www.raywenderlich.com/zh-hans/30818/ios%E5%BA%94%E7%94%A8%E5%B4%A9%E6%BA%83%E6%97%A5%E5%BF ...
- 利用AddressBook.framework框架获取iOS系统通讯录数据
此方法是使用AddressBook.framework框架获取通讯录信息 第一步.在info.plist文件里面配置访问权限 第二步.导入头文件 #import <AddressBook/Add ...
- iOS,应用崩溃日志分析
参考资料:http://www.cocoachina.com/industry/20130725/6677.html 1.获得崩溃日志 2.崩溃日志实例 3.符号化崩溃日志 4.低内存闪退 获得崩溃日 ...
随机推荐
- awk字符串处理
awk 字符串处理函数 awk提供了许多强大的字符串函数,见下表:awk内置字符串函数gsub(r,s) 在整个$0中用s替代rgsub(r,s,t) 在整个t中用s替代rindex(s, ...
- ThinkPHP开发笔记-视图
1.如果要在模板中输出变量,必须在在控制器中把变量传递给模板,系统提供了assign方法对模板变量赋值,无论何种变量类型都统一使用assign赋值,而且assign方法必须在display和show方 ...
- Markdown锚点使用
为了使得博客看起来更加美观,我更倾向于使用索引,但是如何在Markdown使用索引跳到指定位置呢?以下是使用方法: 具体应用场景: (1)文献列表中链接--可以通过锚实现页面内的链接:引用文献中可能需 ...
- ECMAScript6教程目录
ECMAScript 6 简介 let 和 const 命令 数组的解构赋值 字符串的扩展 正则的扩展 数值的扩展 函数的扩展 数组的扩展 对象的扩展 Symbol Set 和 Map 数据结构 Pr ...
- keras运行gan的几个bug解决
http://blog.csdn.net/u012317000/article/details/79211274 https://www.jianshu.com/p/5b1f7004144d
- HTML DOM(二):节点的增删改查
上一篇讲述了DOM的基本知识,从其得知,在DOM眼中,HTML的每个成分都可以看作是节点(文档节点.元素节点.文本节点.属性节点.注释节点,其中,属性节点是属于元素节点),本篇的内容就是通过DOM对这 ...
- 一个不错的JavaScript解析浏览器路径方法
JavaScript中有时需要用到当前的请求路径等涉及到url的情况,正常情况下我们可以使用location对象来获取我们需要的信息,本文从另外一个途径来解决这个问题,而且更加巧妙 方法如下: fun ...
- HDU 5289 尺取
Assignment Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total ...
- UVA-10972 RevolC FaeLoN (边双连通+缩点)
题目大意:将n个点,m条边的无向图变成强连通图,最少需要加几条有向边. 题目分析:所谓强连通,就是无向图中任意两点可互达.找出所有的边连通分量,每一个边连通分量都是强连通的,那么缩点得到bcc图,只需 ...
- Highcharts 基本区域图;Highcharts 使用负数区域图;Highcharts 堆叠区域图;Highcharts 百分比堆叠区域图
Highcharts 基本区域图 配置 chart chart.type 配置项用于设定图表类型,默认为 "line",本章节我们使用 'area'. var chart = { ...