iOS——JSON解析

JSON数据

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它基于 ECMAScript 的一个子集。JSON 采用完全独立于语言的文本格式,但是也使用了类似于 C 语言家族的习惯(包括 C、C++、 C#、Java、JavaScript、Perl、Python 等)。这些特性使 JSON 成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成(一般用于提升网络传输速率)

1. JSON 语法规则

JSON 语法主要的有4条,分别是 :

  1. 数据在键值对中
    数据的书写格式为 : “名称” : “值”(用双引号)
    JSON 的值可以是以下类型 :
    • 数字(整数/浮点数)
    • 字符串(在双引号中)
    • BOOL值(true/false)
    • 数组(方括号中)
    • 对象(大括号中)
    • null
  2. 花括号保存对象

    • 对象在 JSON 中表示为 “{}” 括起来的内容,可以理解为键值对的结构
      即 {key : value}
      对象的值可以为上述集中类型
      取值方法为 : 对象[key]
    • 对象是一个无序的 “名称/值对象” 集合
      一个对象以 “{” 开始并以 “}” 结束
  3. 方括号保存数组

    • 数组在 JSON 中表示为 “[]” 括起来的内容
      即 [“first”]
      数组的元素可以为上述几种类型
    • 数组是 值 的有序集合
      值之间使用 逗号 分隔

    4.* 数据之间由逗号分隔*
    即 {“key” : “value”, “key2” : “value2”}

2. JSON 示例

  • 表示名称/值对象对
{"firstName" : "Lin"}
  • 表示多个名称/值对
{"firstName" : "Hao", "lastName" : "Lin"}

使用 JSON 可以使代码可读性更好,例如上述三个值都是同一记录,因为它们属于同一个对象(大括号括起来)

  • 表示数组
{
    "people" : [
            {"firstName" : "Brett", "lastName" : "McLaughlin", "email" : "abcde"}, 
            {"firstName" : "Jason", "lastName" : "Hunter", "email" : "fghig"}, 
            {"firstName" : "Elliotte", "lastName" : "Harold", "email" : "klmno"}, 
    ]
}

在上述代码中,可以很轻松的看出,只有一个名为 person 的键,该键的值是一个数组,且数组包含三个对象,每个对象记录了名、姓、电子邮件信息

包含多个值

{
    "programmers":[
            {"firstName": "Brett", "lastName": "McLaughlin", "email": "aaaa"},
            {"firstName": "Jason", "lastName": "Hunter", "email": "bbbb"},
            {"firstName": "Elliotte", "lastName": "Harold", "email": "cccc"}
    ],

    "authors":[
            {"firstName": "Isaac", "lastName": "Asimov", "genre": "sciencefiction"},
            {"firstName": "Tad", "lastName": "Williams", "genre": "fantasy"},
            {"firstName": "Frank", "lastName": "Peretti", "genre": "christianfiction"}
    ],

    "musicians":[
            {"firstName": "Eric", "lastName": "Clapton", "instrument": "guitar"},
            {"firstName": "Sergei", "lastName": "Rachmaninoff", "instrument": "piano"}
    ]
}

上述代码可以看出,一共有 3 个键,分别是 programmers、authors、musicians,并且每个键的值是一个数组,并且该数组包含 2 个或 3 个对象,每个对象记录了 名、姓、电子邮件信息

JSON 解析

1. NSJSONSerialization

NSJSONSerialization 是 iOS 5引入的解析 JSON 的类,使用该类,我们可以在 JSON串 和 NSDictionary 与 NSArray 之间转换

1.1 解析程序中的 JSON 串

我们要解析以下 4 个 JSON 串

{"name" : "James", "age" : "30"}
{"user" : {"name" : "James", "age" : "31"}}
[{"name" : "James"}, {"name" : "Jim"}]
{"uesr" : [{"name" : "James"}, {"name" : "Jim"}]}

在 XIB 文件中添加 1 个 UITextView 和 4 个 UIButton,并为 4 个 button 设置 IBAction,为 UITextView 设置 IBOutlet,如图
主界面

  • 解析第一个 JSON 串
// 1. 创建 JSON 字符串
NSString * jsonStr = @"{\"name\" : \"James\", \"age\" : \"30\"}";
// 使用转义字符 “\” 使当前字符串的双引号属于这个字符串的一部分,而不是单独的一个双引号

// 2. 创建 JSON 数据,使用 UTF-8 编码将字符串转换为数据
NSData * jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];

// 3. 解析 jsonData 对象
// 返回值可能会 字典,也可能为 数组,所以用 id 类型接受
id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];

// 4. 判断 jsonObj 的类型
if ([jsonObj isKindOfClass:[NSDictionary class]]) {

        // 因为解析的 JSON 串的最外层为 {},所以它解析完成后的数据便是 字典
        // json 数据是字典类型
        // a. 强制转换为 NSDictionary
        NSDictionary * dic = (NSDictionary *)jsonObj;
        // 此时,解析出来的 dic 就是一个字典,有基本的键和基本的值,所以可以直接取出键所对应的值,但是之后的 3 个却并不是这样,稍后会看到

        // b. 将解析出来的数据赋给 UITextView 并设置为追加内容
        _textView.text = [_textView.text stringByAppendingString:[dic objectForKey:@"name"]];

        _textView.text = [_textView.text stringByAppendingString:@"\n"];

        _textView.text = [_textView.text stringByAppendingString:[dic objectForKey:@"age"]];

    }

运行结果
运行结果

要注意的是这个方法

// 参数 1: 要解析的 JSON 数据,为 NSData 对象
// 参数 2: 解析时的选项,参照下面的枚举
// 参数 3: 错误消息,即解析失败时该怎么办
+ (nullable id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;

NSJSONReadingOptions 枚举

typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
    NSJSONReadingMutableContainers = (1UL << 0), // 解析完成后返回的对象是可变的(NSMutableDictionary/NSMutableArray)
    NSJSONReadingMutableLeaves = (1UL << 1),  // 解析完成后,其中的字符串为 NSMutableString
    NSJSONReadingAllowFragments = (1UL << 2) // 允许解析的 JSON 串的最外层既不是 NSDictionary 也不是 NSArray,但必须是有效的 JSON 串
} NS_ENUM_AVAILABLE(10_7, 5_0);
  • 解析第二个 JSON 串
- (IBAction)onParseJSON2:(id)sender {

    NSString * jsonStr = @"{\"user\" : {\"name\" : \"James\", \"age\" : \"31\"}}";

    NSData * jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];

    id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];

    if ([jsonObj isKindOfClass:[NSDictionary class]]) {

        NSDictionary * dic = (NSDictionary *)jsonObj;

        // 此时,解析出来的 dic 是一个字典,并且键为 @"user",而该键的值又是一个新的字典,所以需要再次使用 objectForKey: 方法,将下一层的字典取出来
        NSDictionary * dicUser = [dic objectForKey:@"user"];

        _textView.text = [_textView.text stringByAppendingString:[dicUser objectForKey:@"name"]];

        _textView.text = [_textView.text stringByAppendingString:@"\n"];

        _textView.text = [_textView.text stringByAppendingString:[dicUser objectForKey:@"age"]];

    }

}

运行结果
这里写图片描述
第二个和第一个基本相似,唯一不同的地方也在代码中指了出来

  • 解析第三个 JSON 串
- (IBAction)onParseJSON3:(id)sender {

    NSString * jsonStr = @"[{\"name\" : \"James\"}, {\"name\" : \"Jim\"}]";

    NSData * jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];

    id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];

    if ([jsonObj isKindOfClass:[NSArray class]]) {

        // jsonObj 是 NSArray 类型
        // a. 强制转换为 NSArray
        NSArray * array = (NSArray *)jsonObj;

        // 因为数组内的元素是 JSON 对象,即 大括号,也就是 字典,所以使用 NSDictionary 对象遍历数组
        for (NSDictionary * dic in array) {

            _textView.text = [_textView.text stringByAppendingString:[dic objectForKey:@"name"]];

            _textView.text = [_textView.text stringByAppendingString:@"\n"];

        }

    }

}

运行结果
运行结果
第三个和前两个不同的是最外层是 “[]” 也就是数组,所以解析出来的就是 NSArray 对象,数组中包含的是 JSON 对象(字典),所以使用 NSDictionary 对象遍历每个元素

  • 解析第四个 JSON 串
- (IBAction)onParseJSON4:(id)sender {

    NSString * jsonStr = @"{\"user\" : [{\"name\" : \"James\"}, {\"name\" : \"Jim\"}]}";

    NSData * jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];

    id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];

    if ([jsonObj isKindOfClass:[NSDictionary class]]) {

        NSDictionary * dic = (NSDictionary *)jsonObj;

        // 解析出来的是一个键为 user 的字典对象,其值为数组
        NSArray * array = [dic objectForKey:@"user"];

        for (NSDictionary * dic in array) {

            _textView.text = [_textView.text stringByAppendingString:[dic objectForKey:@"name"]];

            _textView.text = [_textView.text stringByAppendingString:@"\n"];

        }

    }

}

运行结果
运行结果
这个 JSON 串中显示一个 键为 user 的字典,其值又是一个数组,所以先把键对应的数组取出来,再在数组中遍历每个元素

1.2 从文件中解析

首先自己写了一个简单的 JSON 文件并加入到了项目中,JSON 文件如下

{
    "weatherinfo" : {
        "city" : "北京", "cityid" : "101010100", "temp1" : "15˚C", "temp2" : "5˚C", "weather" : "多云", "ptime" : "08:00"
    } 
}

解析 JSON 文件的代码如下

- (IBAction)onParseJSON:(id)sender {

    // 定义文件路径
    NSString * path = [[NSBundle mainBundle] pathForResource:@"weatherinfo" ofType:@"json"];

    // 系统中有一个默认的 manger
    NSFileManager * fileMgr = [NSFileManager defaultManager];

    // 判断在 path 路径下是否存在 weatherinfo.json
    if ([fileMgr fileExistsAtPath:path]) {

        // 保存 json 文件中的信息,即那些字符串
        NSString * jsonStr = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

        // 将 JSON 字符串 使用 UTF-8 编码为 NSData 对象
        NSData * jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];

        // 解析 NSData 对象的数据
        id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];

        if ([jsonObj isKindOfClass:[NSDictionary class]]) {

            NSDictionary * dic = (NSDictionary *)jsonObj;

            NSDictionary * dicWeatherinfo = [dic objectForKey:@"weatherinfo"];

            _textView.text = [_textView.text stringByAppendingString:[NSString stringWithFormat:@"\n地点: %@\n城市ID: %@\n天气: %@\n最低温度: %@\n最高温度: %@\n时间: %@",
                        [dicWeatherinfo objectForKey:@"city"],
                        [dicWeatherinfo objectForKey:@"cityid"],
                        [dicWeatherinfo objectForKey:@"weather"],
                        [dicWeatherinfo objectForKey:@"temp2"],
                        [dicWeatherinfo objectForKey:@"temp1"],
                        [dicWeatherinfo objectForKey:@"ptime"]]];

        }

    }
    else {

        _textView.text = [_textView.text stringByAppendingString:@"文件未找到"];

        return;
    }

}

运行结果
运行结果

1.3 从网络上解析 JSON 数据

解析如下的数据
http://www.weather.com.cn/data/cityinfo/101010100.html

  • 方法一:使用 NSURL 获取
- (IBAction)onParseJSON:(id)sender {


    // 首先要将网络上的数据与 NSData 联系

    // 创建 URL 对象
    NSURL * url = [NSURL URLWithString:@"http://www.weather.com.cn/data/cityinfo/101010100.html"];

    // 用 url 所对应网络上的数据初始化 NSData 对象
    NSData * jsonData = [NSData dataWithContentsOfURL:url];

    id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];

    if ([jsonObj isKindOfClass:[NSDictionary class]]) {

        NSDictionary * dic = (NSDictionary *)jsonObj;

        NSDictionary * dicWeatherinfo = [dic objectForKey:@"weatherinfo"];

        _textView.text = [_textView.text stringByAppendingString:[NSString stringWithFormat:@"\n地点: %@\n城市ID: %@\n天气: %@\n最高温度: %@\n最低温度: %@\n时间: %@",
                    [dicWeatherinfo objectForKey:@"city"],
                    [dicWeatherinfo objectForKey:@"cityid"],
                    [dicWeatherinfo objectForKey:@"weather"],
                    [dicWeatherinfo objectForKey:@"temp2"],
                    [dicWeatherinfo objectForKey:@"temp1"],
                    [dicWeatherinfo objectForKey:@"ptime"]]];

    }

}

运行结果
运行结果

  • 方法二 使用 NString 获取
- (IBAction)onParseJSON2:(id)sender {

    // 创建 NSURL 对象
    NSURL * url = [NSURL URLWithString:@"http://www.weather.com.cn/data/cityinfo/101010100.html"];

    // 从 url 对应的网络上获取数据,并以 UTF-8 编码的字符串的形式返回
    NSString * jsonStr = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];

    NSData * jsonData = [jsonStr dataUsingEncoding:NSUTF8StringEncoding];

    id jsonObj = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:nil];

    if ([jsonObj isKindOfClass:[NSDictionary class]]) {

        NSDictionary * dic = (NSDictionary *)jsonObj;

        NSDictionary * dicWeatherinfo = [dic objectForKey:@"weatherinfo"];

        _textView.text = [_textView.text stringByAppendingString:[NSString stringWithFormat:@"\n地点: %@\n城市ID: %@\n天气: %@\n最低温度: %@\n最高温度: %@\n时间: %@",
                    [dicWeatherinfo objectForKey:@"city"],
                    [dicWeatherinfo objectForKey:@"cityid"],
                    [dicWeatherinfo objectForKey:@"weather"],
                    [dicWeatherinfo objectForKey:@"temp2"],
                    [dicWeatherinfo objectForKey:@"temp1"],
                    [dicWeatherinfo objectForKey:@"ptime"]]];

    }

}

运行结果
运行结果

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值