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


我们先来看一下后台返回的部分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. 建立、配置和使用Activity——Activity

    Activity是Android应用中最重要.最常见的应用组件(此处的组件是粗粒度的系统组成部分,并非指界面控件:widget).Android应用的一个重要组成部分就是开发Activity,下 面将 ...

  2. webview 设置编码

    WebSettings settings = webView.getSettings(); // 设置页面编码 settings.setDefaultTextEncodingName("ut ...

  3. doubango(3)--协议栈的启动过程

    协议栈启动的上层接口 对于Doubango中得sip协议栈,是通过SipStack类粘合上层代码与底层代码的,该类定义在SipStack.h中,实现在SipStack.cxx中.当构造好一个SipSt ...

  4. Bootstrap入门(三十)JS插件7:警告框

    Bootstrap入门(三十)JS插件7:警告框 通过这个插件可以为警告信息添加点击以及消失的功能. 当使用一个.close按钮,它必须是第一个子元素.alert-dismissible,并没有文字内 ...

  5. IEcss样式,行高的问题

    input的文本内容显示一定要用line-height,不然会出现内容错位的问题

  6. iOS之内存分析

    静态内存分析(Product->Analyze) 静态内存分析是不运行程序,直接对代码进行分析. 但是没有真正分配内存,根据代码的上下文的语法结构,来分析是否有内存泄露 缺点:不一定准确,但是如 ...

  7. python爆破定长密码脚本

    def get_pwd(str, num):#str为可选字符集,num为密码长度 if(num == 1): for x in str: yield x else: for x in str: fo ...

  8. gevent调度流程解析

    gevent是目前应用非常广泛的网络库,高效的轮询IO库libev加上协程(coroutine),使得gevent的性能非常出色,尤其是在web应用中.本文介绍gevent的调度流程,主要包括geve ...

  9. db2_errroecode

    sqlcode sqlstate  说明 000 00000 SQL语句成功完成   01xxx SQL语句成功完成,但是有警告 +012 01545 未限定的列名被解释为一个有相互关系的引用 +09 ...

  10. 一个想法(续三):一份IT技术联盟创业计划书,开启众筹创业征程

    写在创业计划书之前的话: 昨天在闪存里我@了dudu,说:我要借钱,不久dudu回了我:傍个富婆. 当然,dudu以为我是玩笑,其实,我的确是开玩笑的,哈. 不过我正在执行一个创业计划,如果启动,我会 ...