JSON 解析常用的第三方框架有:JSONKit、SBJson、TouchJSON,其性从左到右依次降低。但是从IOS5开始,APPLE提供了对json的原生支持(NSJSONSerialization)。
JSONKit 已经在 2012 年停止更新,官方说 JSONKit 比苹果原生的 NSJSONSerialization 解析速度快,实测其实苹果原生的 NSJSONSerialization 解析速度更快。
本文就只介绍ios原生的NSJSONSerialization和常用的JSONKit:
1、系统方式 JSON 数据解析
解析 json 数据
/*
反序列化:将从服务器接收到的二进制数据转换成 NSDictionary / NSArray 的过程,简化程序开发,便于后续的字典转模型。
数据必须符合 json 格式,用来接收的容器必须和 json 的最外层保持一致。
NSJSONReadingMutableContainers = (1UL << 0), // 容器可变,NSMutableDictionary 或 NSMutableArray。
NSJSONReadingMutableLeaves = (1UL << 1), // 叶子可变,返回的 JSON 对象中字符串的值为 NSMutableString。
NSJSONReadingAllowFragments = (1UL << 2) // 允许 JSON 字符串最外层既不是 NSArray 也不是 NSDictionary,
但必须是有效的 JSON 片段
反序列化中的可变不可变,实际用处不大,后续紧接着就是字典转模型。因此输入 0 效率最好。如果今后看到 ** 类型的参数,
又不想获取对应的内容,传递 NULL 即可。传入 nil 不会抱错。
*/
// 从本地文件中读取数据
NSData *jsonData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"JsonDataFile" ofType:@"txt"]];
// 解析 json 数据
id result = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:NULL];
生成 json 数据:
/*
序列化:将字典或者数组发送给服务器之前,转换成二进制数据,方便网络传输。
生成 json 数据的对象必须满足以下条件:
对象最外层必须是 NSArray 或者 NSDictionary。
容器内的所有数据必须是 NSString, NSNumber, NSArray, NSDictionary, 或者 NSNull 类型。
字典的所有 key 都是 NSString 格式。
NSNumber 不能是 NaN(非数值) 或者 infinity(无限大)。
NSJSONWritingOptions:
NSJSONWritingPrettyPrinted = (1UL << 0) 漂亮的格式打印
使用 0 时,生成的数据格式如下,将 JSON 数据发送给服务器时可以使用该种格式。
{"age":8,"score":99,"add":"beijing","name":"xiaoxin"}
使用 1 时,生成的数据格式如下,将 JSON 数据保存到本地时可以使用该种格式。
{
"age" : 8,
"score" : 99,
"add" : "beijing",
"name" : "xiaoxin"
}
*/
// Foundation object
NSDictionary *dicitionary = @{@"name":@"xiaoxin", @"age":@8, @"score":@99, @"add":@"beijing"};
// 判断 Foundation 对象是否可以生成 json 数据
BOOL isValid = [NSJSONSerialization isValidJSONObject:dicitionary];
// 生成 json 数据
NSData *jData = [NSJSONSerialization dataWithJSONObject:dicitionary options:0 error:NULL];
2.JSONKit 方式 JSON 数据解析
SONDecoder 方式解析
// 从本地文件中读取数据
NSData *jsonData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"JsonDataFile" ofType:@"txt"]];
id result = [[JSONDecoder decoder] objectWithData:jsonData];
NSLog(@"%@ %@", result, [result class]);
JSONString 解析
// 单层 JSONString 解析
/*
如果 json 是 “单层” 的,即 value 都是字符串、数字,可以使用 objectFromJSONString
*/
// 单层 JSONString 数据
NSString *jsonStr1 = @"{\"a\":123, \"b\":\"abc\"}";
// 返回可变结果使用 mutableObjectFromJSONString 方法
NSDictionary *jsonStrDic1 = [jsonStr1 objectFromJSONString];
// 嵌套 JSONString 解析
/*
如果 json 有嵌套,即 value 里有 array、object,如果再使用 objectFromJSONString,程序可能会报错,
测试结果表明:使用由网络或得到的 php/json_encode 生成的 json 时会报错,但使用 NSString 定义的 json 字符串时,
解析成功,最好使用 objectFromJSONStringWithParseOptions:
*/
// 嵌套 JSONString 数据
NSString *jsonStr2 = @"{\"a\":123, \"b\":\"abc\", \"c\":[456, \"hello\"], \"d\":{\"name\":\"张三\", \"age\":\"32\"}}";
// 返回可变结果使用 mutableObjectFromJSONStringWithParseOptions 方法
NSDictionary *jsonStrDic2 = [jsonStr2 objectFromJSONStringWithParseOptions:JKParseOptionLooseUnicode];
生成 JSONString 数据
// NSString -> JSONString
NSString *str1 = @"{a\":123, \"b\":\"abc\"}";
// 默认参数为 JKSerializeOptionNone,includeQuotes 为 YES
NSString *jsonStrFromStr1 = [str1 JSONString];
// includeQuotes 为 NO 时,编码后的数据最外层不含引号
NSString *jsonStrFromStr2 = [str1 JSONStringWithOptions:JKSerializeOptionNone includeQuotes:NO error:nil];
// NSArray/NSDictionary -> JSONString
NSDictionary *dic1 = @{@"name":@"xiaoxin", @"age":@8, @"Info":@{@"score":@99, @"add":@"beijing"}};
// 默认参数为 JKSerializeOptionNone
NSString *jsonStrFromDic1 = [dic1 JSONString];
NSString *jsonStrFromDic2 = [dic1 JSONStringWithOptions:JKSerializeOptionEscapeUnicode error:nil];
JSONData 解析
// 单层 JSONData 解析
NSData *jsonData1 = [@"{\"a\":123, \"b\":\"abc\"}" dataUsingEncoding:NSUTF8StringEncoding];
// 返回可变结果使用 mutableObjectFromJSONData 方法
NSDictionary *jsonDataDic1 = [jsonData1 objectFromJSONData];
// 嵌套 JSONData 解析
// 从本地文件中读取数据
NSData *jsonData2 = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"JsonDataFile" ofType:@"txt"]];
// 返回可变结果使用 mutableObjectFromJSONStringWithParseOptions 方法
NSDictionary *jsonDataDic2 = [jsonData2 objectFromJSONDataWithParseOptions:JKParseOptionLooseUnicode];
生成 JSONData 数据
// NSString -> JSONData
NSString *str2 = @"{a\":123, \"b\":\"abc\"}";
// 默认参数为 JKSerializeOptionNone,includeQuotes 为 YES
NSData *jsonDataFromStr1 = [str2 JSONData];
NSData *jsonDataFromStr2 = [str2 JSONDataWithOptions:JKSerializeOptionNone includeQuotes:NO error:nil];
// NSArray/NSDictionary -> JSONData
NSDictionary *dic2 = @{@"name":@"xiaoxin", @"age":@8, @"Info":@{@"score":@99, @"add":@"beijing"}};
// 默认参数为 JKSerializeOptionNone
NSData *jsonDataFromDic1 = [dic2 JSONData];
NSData *jsonDataFromDic2 = [dic2 JSONDataWithOptions:JKSerializeOptionEscapeUnicode error:nil];
补充:
利用字典NSDictionary转换为键/值格式的数据。
// 如果数组或者字典中存储了 NSString, NSNumber, NSArray, NSDictionary, or NSNull 之外的其他对象,就不能直接保存成文件了.也不能序列化成 JSON 数据.
NSDictionary *dict = @{@"name" : @"me", @"do" : @"something", @"with" : @"her", @"address" : @"home"};
// 1.判断当前对象是否能够转换成JSON数据.
// YES if obj can be converted to JSON data, otherwise NO
BOOL isYes = [NSJSONSerialization isValidJSONObject:dict];
if (isYes) {
NSLog(@"可以转换");
/* JSON data for obj, or nil if an internal error occurs. The resulting data is a encoded in UTF-8.
*/
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:NULL];
/*
Writes the bytes in the receiver to the file specified by a given path.
YES if the operation succeeds, otherwise NO
*/
// 将JSON数据写成文件
// 文件添加后缀名: 告诉别人当前文件的类型.
// 注意: AFN是通过文件类型来确定数据类型的!如果不添加类型,有可能识别不了! 自己最好添加文件类型.
[jsonData writeToFile:@"/Users/SunnyBoy/Sites/JSON_XML/dict.json" atomically:YES];
NSLog(@"%@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
} else {
NSLog(@"JSON数据生成失败,请检查数据格式");
}
通过JSON序列化可以转换数组,但转换结果不是标准化的JSON格式。
NSArray *array = @[@"qn", @18, @"ya", @"wj"];
BOOL isYes = [NSJSONSerialization isValidJSONObject:array];
if (isYes) {
NSLog(@"可以转换");
NSData *data = [NSJSONSerialization dataWithJSONObject:array options:0 error:NULL];
[data writeToFile:@"/Users/SunnyBoy/Sites/JSON_XML/base" atomically:YES];
} else {
NSLog(@"JSON数据生成失败,请检查数据格式");
}