IOS开发中使用writeToFile时的注意事项
总会有一些坑在前面等着你
我们先来看一下后台返回的部分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得了,于是将'[userNameDictsetObject:dict[@"userName"]forKey:dict[@"userCode"]];'换成了'[userNameDictsetObject: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=[NSMutableArrayarray]; for(NSDictionary*dictinlist){ for(NSString*keyindict){ if([dict[key]isKindOfClass:[NSArrayclass]]){ [contactListArrayaddObjectsFromArray:dict[key]]; } } } NSMutableDictionary*userNameDict=[NSMutableDictionarydictionary]; NSMutableDictionary*avatarurlDict=[NSMutableDictionarydictionary]; NSMutableDictionary*avatarurlAndNameDict=[NSMutableDictionarydictionary]; for(NSDictionary*dictincontactListArray){ if(dict[@"userId"]==nil){ return; } [userNameDictsetObject:dict[@"userName"]forKey:dict[@"userId"]]; NSString*url=dict[@"avatarUrl"]; NSString*avatarUrl=[CPUtilgetThumUrl:urlsize:CGSizeMake(200,200)]; [avatarurlDictsetObject:avatarUrlforKey:dict[@"userId"]]; if(dict[@"userName"]==nil){ return; } [avatarurlAndNameDictsetObject:avatarUrlforKey:dict[@"userName"]]; } NSString*path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES).firstObject; NSString*userNameDictPath=[pathstringByAppendingPathComponent:@"userNameDict.plist"]; NSString*avatarurlDictPath=[pathstringByAppendingPathComponent:@"avatarurlDict.plist"]; NSString*avatarurlAndNameDictPath=[pathstringByAppendingPathComponent:@"avatarurlAndNameDict.plist"]; [userNameDictwriteToFile:userNameDictPathatomically:YES]; [avatarurlDictwriteToFile:avatarurlDictPathatomically:YES]; [avatarurlAndNameDictwriteToFile:avatarurlAndNameDictPathatomically:YES]; }
分析问题
实际开发当中,总是有细节的东西,虽然有时候觉得,这些东西太基础,但是就在这些基础的知识上,我们却忽略了一些本应该注意的点.好比说我们明明知道向数组中添加元素的时候,元素不能为空,记得考虑为nil,null的情况.这谁都知道,但是却最容易被忽略,因为你无法确定后台的数据返回什么,包括那些规范文档明确要求不能为nil的字段,都有可能返回一个nilorNull.这个时候开始想静静了.明白这个世界其实没有必然的东西.另外,数组越界问题也一直都在,当然为了防止App直接闪退,你可以选择去覆盖系统的方法......好了,言归正传.我们看一下苹果官方文档,回顾一下基础的东西,文档中关于NSDictionary和writeToFile有下面两段内容
NSDictionary
*Akey-valuepairwithinadictionaryiscalledanentry.Eachentryconsistsofoneobjectthatrepresentsthekeyandasecondobjectthatisthatkey'svalue.Withinadictionary,thekeysareunique.Thatis,notwokeysinasingledictionaryareequal(asdeterminedbyisEqual(_:)).Ingeneral,akeycanbeanyobject(providedthatitconformstotheNSCopyingprotocol—seebelow),butnotethatwhenusingkey-valuecodingthekeymustbeastring(seeAccessingObjectProperties).Neitherakeynoravaluecanbenil;ifyouneedtorepresentanullvalueinadictionary,youshoulduseNSNull.*
这里说,字典中的key可以是遵守NSCopying协议的任何对象类型,但是key-valuecoding中的key必须是一个string.
'-(BOOL)writeToFile:(NSString*)pathatomically:(BOOL)useAuxiliaryFile;'
Thismethodrecursivelyvalidatesthatallthecontainedobjectsarepropertylistobjects(instancesofNSData,NSDate,NSNumber,NSString,NSArray,orNSDictionary)beforewritingoutthefile,andreturnsNOifalltheobjectsarenotpropertylistobjects,sincetheresultantfilewouldnotbeavalidpropertylist.
这里描述了写入文件的对象要求,也就是平时常用的NSData,NSDate,NSNumber,NSString,NSArray,orNSDictionary这些类型,当然自定义类型不可以.
解决问题
当然最后的处理就是将NSNumber格式化为NSString,看下代码
NSString*dictKey=[NSStringstringWithFormat:@"%@",dict[@"userId"]]; [userNameDictsetObject:dict[@"userName"]forKey:dictKey];
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持毛票票!