总会有一些坑在前面等着你


我们先来看一下后台返回的部分json数据,稍后再来分析问题,仔细看一下userId和userCode两个字段,其他不用看


"list": [{
"classId": 5000285,
"className": "考勤(A)班",
"schoolId": 50011,
"schoolName": "星星局测中学25",
"classLeaderUserId": 2000163,
"parentList": [{
"userId": 2000790,
"userName": "zhaomin",
"gender": "0",
"mobile": "15071362222",
"email": "",
"areaCode": "440105",
"avatarUrl": "",
"userCode": "2000790",
"id": 1542,
"roleType": 2,
"nickName": "zhaomin"
}, {
"userId": 2000846,
"userName": "刘玄德",
"gender": "1",
"mobile": "18825113388",
"email": "",
"areaCode": "440105",
"avatarUrl": "",
"userCode": "2000846",
"id": 1631,
"roleType": 2,
"nickName": "刘玄德"
}],

问题背景


这个问题是在我集成环信IM的时候,由于需要处理用户头像和昵称问题,所以会将联系人的头像url和用户昵称做一个本地缓存,缓存的方式就是采用简单的写入plist文件来处理.之所以使用plist,是因为简单方便,而且可以满足开发,所以就没有采用其他的缓存方式.

问题就是出现在写入plist文件上面.

遇到问题


在获取到后台返回的联系人数据以后,我就将返回的list进行筛选,只是筛选出所需的用户姓名和头像地址.返回字段中,userId和userCode看似一样,其实解析出来,前者是NSNuber类型,后者是NSString类型,当时只记得后台直接使用Sqlite语句,将userCode=userId,根本没有考虑到类型问题.心想,既然这样,不如直接使用userId得了,于是将' [userNameDict setObject:dict[@"userName"] forKey:dict[@"userCode"]];'换成了'[userNameDict setObject:dict[@"userName"] forKey:dict[@"userId"]];'.问题就是出现在换了一个字段上.


刚开始没有发现问题,因为之前一直使用userCode字段取值作为字典的key,所以在本地已经有了缓存.直到有一天,重新安装App测试时才发现,聊天界面的头像和昵称都不在显示,才最终想到当初换了了一个字段取值.


但是,更换为userId后,打印出来的字典一模一样,就是writeToFile写入plist时总是失败.后来使用isEqualToDictionary方法比较两个字典又是不一样的.问题实在难找,当然解决办法就是切换为原来的userCode,但是遇到问题一向不想通过回避的方式去解决,所以就排查原因,甚至去比较过所有的key和value值,发现还是一样.最后,感觉实在找不出问题所在,于是去查看返回数据,于是便发现了,字段userId和userCode所对应的Value值的类型是不一样的.这才得出一下结论


如果是可变字典,那么在使用'setObject: forKey:'方法时,如果key使用的是NSNumber类型的key,会导致writeToFile失败.

至于为什么是这样,有待进一步研究,当然,如果有人遇到过并找出原因,也可以回复一下,相互学习,共同进步.


附上当时代码


- (void)saveContactListDict:(id)list { NSMutableArray *contactListArray = [NSMutableArray array];
for (NSDictionary *dict in list) {
for (NSString *key in dict) {
if ([dict[key] isKindOfClass:[NSArray class]]) { [contactListArray addObjectsFromArray:dict[key]];
}
}
} NSMutableDictionary *userNameDict = [NSMutableDictionary dictionary];
NSMutableDictionary *avatarurlDict = [NSMutableDictionary dictionary];
NSMutableDictionary *avatarurlAndNameDict = [NSMutableDictionary dictionary];
for (NSDictionary *dict in contactListArray) {
if (dict[@"userId"] == nil) {
return;
}
[userNameDict setObject:dict[@"userName"] forKey:dict[@"userId"]];
NSString *url =dict[@"avatarUrl"];
NSString *avatarUrl = [CPUtil getThumUrl:url size:CGSizeMake(200, 200)];
[avatarurlDict setObject:avatarUrl forKey:dict[@"userId"]];
if (dict[@"userName"] == nil) {
return;
}
[avatarurlAndNameDict setObject:avatarUrl forKey:dict[@"userName"]]; } NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *userNameDictPath = [path stringByAppendingPathComponent:@"userNameDict.plist"];
NSString *avatarurlDictPath = [path stringByAppendingPathComponent:@"avatarurlDict.plist"];
NSString *avatarurlAndNameDictPath = [path stringByAppendingPathComponent:@"avatarurlAndNameDict.plist"];
[userNameDict writeToFile:userNameDictPath atomically:YES];
[avatarurlDict writeToFile:avatarurlDictPath atomically:YES];
[avatarurlAndNameDict writeToFile:avatarurlAndNameDictPath atomically:YES]; }

分析问题

实际开发当中,总是有细节的东西,虽然有时候觉得,这些东西太基础,但是就在这些基础的知识上,我们却忽略了一些本应该注意的点.好比说我们明明知道向数组中添加元素的时候,元素不能为空,记得考虑为nil,null的情况.这谁都知道,但是却最容易被忽略,因为你无法确定后台的数据返回什么,包括那些规范文档明确要求不能为nil的字段,都有可能返回一个nil or Null .这个时候开始想静静了.明白这个世界其实没有必然的东西.另外,数组越界问题也一直都在,当然为了防止App直接闪退,你可以选择去覆盖系统的方法......好了,言归正传.我们看一下苹果官方文档,回顾一下基础的东西,文档中关于NSDictionary和writeToFile有下面两段内容

NSDictionary

A key-value pair within a dictionary is called an entry. Each entry consists of one object that represents the key and a second object that is that key’s value. Within a dictionary, the keys are unique. That is, no two keys in a single dictionary are equal (as determined by isEqual(_

关于开发中使用writeToFile时的注意事项的更多相关文章

  1. iphone 开发中使用zbar时遇到的几个典型问题解决方法。

    iphone 开发中使用zbar时遇到的几个典型问题解决方法.   在近期的一个ios项目中使用到了一个二维码扫描库(Qrcode)--ZBar, 期间遇到2个问题.   1. zbar下载后使用其l ...

  2. IOS开发中滑动页面时NSTimer停止的问题

    我们在做倒计时的时候,发现当你手指按着屏幕不放,拖动tableView滑动的时候,写在cell上得倒计时停止倒计时,松开继续倒计时.研究发现就是拖动tableView滑动时,NSTimer停止了. 这 ...

  3. 直接添加viewController中的view时的注意事项

    直接添加viewController中的view时需要注意一个问题,比如: MyTestViewController *vc = [MyTestViewController new]; [self.v ...

  4. Android开发中使用数据库时出现java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.

    最近在开发一个 App 的时候用到了数据库,可是在使用数据库的时候就出现了一些问题,在我查询表中的一些信息时出现了一下问题: Caused by: java.lang.IllegalStateExce ...

  5. vue开发中,build时css打包报错

    vue在打包的时候css报错,首先声明的这个并没有解决webpack本身的问题,本来这个也是一个警示,不会影响代码正常运行 这个是因为我在多个页面引入了同一个css文件,webpack打包时候对css ...

  6. 开发中使用UEditor编辑器的注意事项

    最近在一个刚结束的一个项目中使用到了UEditor编辑器,下面总结一下遇到的问题以及使用时需要注意的地方: 1. 使用UEditor插件需要先对其进行路径配置: 在ueditor.config.js文 ...

  7. Golang中进行reslice时的注意事项

    先看下面代码: package main import "fmt" func main() { slice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8} ...

  8. 修改NSMutableArray中的元素时的注意事项

    最近做项目遇到从文件加载数组,并对数组中的元素进行操作的问题,特意写了个Demo,记录下要注意的东西: 代码如下: NSArray *array = @["]; NSMutableArray ...

  9. 在构造函数中使用new时的注意事项

    果然,光看书是没用的,一编程序,很多问题就出现了-- 注意事项: 1. 如果构造函数中适用了new初始化指针成员,则构析函数中必须要用delete 2. new与delete必须兼容,new对应del ...

随机推荐

  1. UVa 706 & ZOJ 1146 LC-Display

    题目大意:给你一个数字n和字体大小s,输出数字的液晶显示.直接模拟,代码如下: #include <stdio.h> void draw(int n,int s,int row) { in ...

  2. PHP检测获取内存信息

    PHP也可以检测获取到Windows的内存信息,而且代码还挺简单,无意发现的,觉得以后能用上,在此与大家分享. 本代码将得到总内存.初始使用等内存信息: <?php echo "初始: ...

  3. shell相关命令

    1.shell是什么? 从用户角度:shell是用户与Linux沟通的桥梁 从程序员角度:shell本身是一种用C语言编写的程序 shell担任了翻译的角色,将用户输入的命令翻译成Linux能够识别的 ...

  4. Angular - - angular.Module

    angular.Module Angular模块配置接口. 方法: provider(name,providerType); name:服务名称. providerType:创建一个服务的实例的构造函 ...

  5. Shell 基础

    1.结构        #!指定执行脚本的shell  #!/bin/sh        # 注释行        命令和控制结构    2.修改权限        chmod +x ...    3 ...

  6. jdbc数据连接池dbcp要导入的jar包

    jdbc数据连接池dbcp要导入的jar包 只用导入commons-dbcp-x.y.z.jarcommons-pool-a.b.jar

  7. 让Flash支持Stage3D

    如要需要支持Stage3D,采用GPU来渲染,需要设置wmode="direct",在FB中,对于web和air设置方法不同: 1.web: 需要在web的html模板中,添加参数 ...

  8. JavaScript中this的指向问题

    this是面向对象语言中一个重要的关键字,理解并掌握该关键字的使用对于我们代码的健壮性及优美性至关重要.而javascript的this又有区别于Java.C#等纯面向对象的语言,这使得this更加扑 ...

  9. JS加载相对路径脚本的方法 - 汇总

    js加载脚本的方式有很多,但是各有各的用途. 最近公司https项目改造,对于资源文件这一块,也是遇到一些问题,现在就来总结一下,怎样改造https的脚本吧~! 方法1.借助服务端语言如PHP,输入当 ...

  10. Cms 总结(转)

    提起开源cms,大家第一想到的是php的cms,因为php开源的最早,也最为用户和站长们认可,随着各大cms系统的功能的不断完善和各式各样的开源cms的出现,.net和java的高端的cms系统也逐渐 ...