下班之前被一个 Bug托住了,后台返回了一段类似下面这样的 JSON 字符串,解析老是出问题的。
{
"name" = "yang",
age = 14,
id = 01,
},
{
"name" = "Tang",
age = 15,
id = 03,
}
就是显示某些字段参数没有加引号,不知道是什么情况,最后貌似发现与这个又无关啦。。。
以为解析出问题了,于是决定先来了解下 JSON,它作为一种轻量级的数据交换格式,json正在逐步取代xml,成为网络数据的通用格式。目前在我们的 app 中基本都是JSON,以前我们也常用SBJSON,JSONKit,当然现在也有用的,但是目前来说,用系统的解析 JSON 也可以满足我们的大部分需求,性能也是比较好的,此处先来记录下系统NSJSONSerialization。
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
NSJSONReadingMutableContainers = (1UL << 0),
NSJSONReadingMutableLeaves = (1UL << 1),
NSJSONReadingAllowFragments = (1UL << 2)
} NS_ENUM_AVAILABLE(10_7, 5_0);
参数 NSJSONReadingOptions
- NSJSONReadingMutableContainers
// 创建出来的数组和字典就是可变 - NSJSONReadingMutableLeaves
// 数组或者字典里面的字符串是可变的(暂时不太好用) - NSJSONReadingAllowFragments
// 意思是需要格式化的json字符串最外层可以不是数组和字典,只要是正确的json格式就行。
推荐使用 ** NSJSONReadingMutableContainers**
NSError *error = nil;
NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
if (error) {
NSLog(@"error == %@",error.description);
}
然而并没有打印类似Error Domain=NSCocoaErrorDomain Code=3840
的错误,所以继续看是不是 YYModel 用错了
最后我总结出来就是如何解析一个类似的数据:
NSDictionary *testDic = @{@"groupId":@"01",
@"result":@[
@{@"name":@"Lucy", @"sex":@"male"},
@{@"name":@"Lily", @"sex":@"feMale"},
@{@"name":@"Limei", @"sex":@"male"}
]
};
此处我设置 GroupUserModel 和 UserModel
@interface GroupUserModel : NSObject<YYModel>
@property (nonatomic, copy) NSString *groupId;
@property (nonatomic, strong) NSArray *result;
@end
#import "GroupUserModel.h"
#import "UserModel.h"
@implementation GroupUserModel
// 包含
+ (NSDictionary *)modelContainerPropertyGenericClass {
return @{
@"result" : [UserModel class],
@"groupId" : @"groupId"
};
}
// 白名单
+ (NSArray *)modelPropertyWhitelist {
return @[@"result",
@"groupId"];
}
@end
@interface UserModel : NSObject<YYModel>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *sex;
@end
#import "UserModel.h"
@implementation UserModel
// custom
+ (NSDictionary *)modelCustomPropertyMapper {
return @{@"name" : @"name",
@"sex" : @"sex",
};
}
// 白名单
+ (NSArray *)modelPropertyWhitelist {
return @[@"name",
@"sex"];
}
@end
解决
self.groupUserModel = [GroupUserModel yy_modelWithDictionary:testDic];
self.dataArray = [NSMutableArray arrayWithArray:self.groupUserModel.result];
for (UserModel *model in self.dataArray) {
NSLog(@"name === %@",model.name);
}
我之前一直写错的原因是下面两个方法写反了
+ (instancetype)arrayWithObject:(ObjectType)anObject;
+ (instancetype)arrayWithArray:(NSArray<ObjectType> *)array;
问题二: 有时我们Model中 .m 文件中写下面几个方法,老是没有提示,需要人工复制。。。
+ (nullable NSDictionary<NSString *, id> *)modelContainerPropertyGenericClass;
+ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper;
+ (nullable NSArray<NSString *> *)modelPropertyWhitelist;
+ (nullable NSArray<NSString *> *)modelPropertyBlacklist;
其实只要让 model 遵从<YYModel>协议就 OK 啦
问题三:直接用数组转 Model
@interface NSDictionary (YYModel)
+ (nullable NSDictionary *)yy_modelDictionaryWithClass:(Class)cls json:(id)json;
注意这个方法,直接套就 OK 啦
总的来说,github 中的说明文档足够可以满足我们的需求,细心阅读,我出问题也是没有详细了解的原因。
备注参考
https://github.com/ibireme/YYModel
http://zhizhi.betahouse.us/2015/11/27/jsonshu-ju-jie-xi-ios/