美文网首页
网络请求之JSON和XML

网络请求之JSON和XML

作者: WenJim | 来源:发表于2017-11-24 13:25 被阅读31次

    1. JSON

    • 什么是JSON

      • JSON是一种轻量级的数据格式,一般用于数据交互
      • 服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外)
    • JSON的格式很像OC中的字典和数组

    {"name" : "jack", "age" : 10}
    {"names" : ["jack", "rose", "jim"]}
    
    • 标准JSON格式的注意点:key必须用双引号

    • 要想从JSON中挖掘出具体数据,得对JSON进行解析

      • JSON 转换为 OC数据类型

    1.1JSON – OC 转换对照表

    JSON OC
    大括号{} NSDictionary
    中括号[] NSArray
    双引号"" NSString
    数字10、10.8 NSNumber

    1.2 JSON解析方案

    • 在iOS中,JSON的常见解析方案有4种
      • 第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差)

      • 苹果原生(自带):NSJSONSerialization(性能最好)

        • NSJSONSerialization的常见方法
          • JSON数据 -->  OC对象 (反序列化)
    + (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
    
    • OC对象 --> JSON数据 (序列化)
    + (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
    

    1.3 客户端解析来自服务器的JSON过程

    客户端解析来自服务器的JSON过程.png

    代码如下:

    #define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
    #define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
    #import "ViewController.h"
    
    @interface ViewController ()
    
    @property (nonatomic,strong) UIButton * btn;
    
    @end
    
    @implementation ViewController
    
    -(UIButton *)btn
    {
        if (!_btn) {
            _btn = [UIButton buttonWithType:UIButtonTypeCustom];
            
            _btn.frame = CGRectMake(SCREENWIDTH / 2 - 75, SCREENHEIGHT / 2 - 15, 150, 30);
            [_btn setTitle:@"登录" forState:UIControlStateNormal];
            [_btn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
            [_btn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
            
        }
        return _btn;
    }
    
    -(void)clickBtn:(UIButton *)btn
    {
    //    [self jsonToOC];
        
    //    [self JSONWithOC];
        
    //    [self OCToJson];
        
        [self test];
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        
        [self.view addSubview:self.btn];
    }
    
    -(void)jsonToOC
    {
        // 1. 确定URL
        NSURL * url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=132&pwd=123&type=JSON"];
        
        // 2. 创建请求对象
        NSURLRequest * request = [NSURLRequest requestWithURL:url];
        // 3. 发送网络请求
        [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
            
            
            // data --> 本质上是一个json字符串
            // 4. 解析JSON
            //        NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
            
            // JSON --> OC对象 反序列化
            /*
             第一参数: JSON的二进制数据
             第二参数:
             第三参数: 错误信息
             */
            /*
             NSJSONReadingMutableContainers = (1UL << 0),  可变字典和数组
             NSJSONReadingMutableLeaves = (1UL << 1),       内部所有的字符串都是可变的,ios7之后有问题,一般不用
             NSJSONReadingAllowFragments = (1UL << 2)       既不是字典,也不是数组,则必须使用该枚举值
             */
            
            //        NSDictionary *dic =  [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
            //        NSLog( @"解析到的数据: %@",dic[@"error"]);
            
            NSString * str = @"\"asdasdasdasd\"";
            id obj =  [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
            NSLog( @"解析到的数据: %@-------%@",[obj class],obj);
        }];
    }
    
    -(void)JSONWithOC
    {
    //    NSString * strM = @"\{\"error\":\"用户名不存在\"}";
    //    NSString * strM = @"[\"error\",\"用户名不存在\"]";
    //    NSString * strM = @"\"dasdqwdxc\"";
    //    NSString * strM = @"false";
    //    NSString * strM = @"true";
        NSString * strM = @"null";
        
        id obj = [NSJSONSerialization JSONObjectWithData:[strM dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:0];
        
        NSLog(@"%@------%@",[obj class],obj);
        
        /*
         
         JSON   OC
         {}     @{} 字典
         []     @[] 数组
         ""     @""
         flase  NSNumber  0
         true   NSNumber  1
         null   NSNull 为空
         */
        
        
        // nil
        [NSNull null];  // 该方法获得的是一个单例,表示为空,可以用在字典或者是数组中
    }
    
    -(void)OCToJson
    {
        NSDictionary * dicM = @{
                                @"name":@"CWJ",
                                @"age":@25
                                };
        
        NSArray * arrM = @[@"123",@"456"];
        
        
        // 注意: 并不是所有的OC对象都能转换为JSON
        /*
         - Top level object is an NSArray or NSDictionary 最外层必须是  NSArray or NSDictionary
         - All objects are NSString, NSNumber, NSArray, NSDictionary, or NSNull 所有的元素必须是 NSString, NSNumber, NSArray, NSDictionary, or NSNull
         
         - All dictionary keys are NSStrings    字典里所有的key都必须是  NSStrings类型的
         - NSNumbers are not NaN or infinity    NSNumbers不能是无穷大
         */
        NSString * strM = @"hahahah"; // 不能转换
        BOOL isValid =  [NSJSONSerialization isValidJSONObject:strM];
        if (!isValid) {
            NSLog(@"是否转换:%zd",isValid);
            return;
        }
        
        
        // OC --> JSON 序列化
        /*
         第一参数: 要转换的OC对象
         第二参数: 选项 NSJSONWritingPrettyPrinted  排版 美观
         第三参数:错误信息
         */
        /*
         没排版的模式: {"name":"CWJ","age":25}
         排版的模式:
         {
         "name" : "CWJ",
         "age" : 25
         }
         */
       NSData * data =  [NSJSONSerialization dataWithJSONObject:arrM options:NSJSONWritingPrettyPrinted error:nil];
        
        NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    }
    
    -(void)test
    {
        NSArray * arrM = [NSArray arrayWithContentsOfFile:@"/Users/WJim/Desktop/GITEE/DuoXianChengDeXueXi/Day15/01-掌握JSON解析/apps.plist"];
        NSLog(@"%@",arrM);
        
    //    [arrM writeToFile:@"/Users/WJim/Desktop/GITEE/DuoXianChengDeXueXi/Day15/01-掌握JSON解析/123.json" atomically:YES];
        
        
        // OC --> JSON
        NSData * data  = [NSJSONSerialization dataWithJSONObject:arrM options:NSJSONWritingPrettyPrinted error:0];
        
        [data writeToFile:@"/Users/WJim/Desktop/GITEE/DuoXianChengDeXueXi/Day15/01-掌握JSON解析/123.json" atomically:YES];
        
    }
    
    @end
    

    2. XML

    • 什么是XML

      • 全称是Extensible Markup Language,译作“可扩展标记语言”
      • 跟JSON一样,也是常用的一种用于交互的数据格式
      • 一般也叫XML文档(XML Document)
    • XML举例

    <videos>
        <video name="小黄人 第01部" length="30" />
        <video name="小黄人 第02部" length="19" />
        <video name="小黄人 第03部" length="33" />
    </videos>
    

    2.1 XML语法

    • 一个常见的XML文档一般由以下部分组成
      • 文档声明
      • 元素(Element)
      • 属性(Attribute)

    2.1.1 XML语法 – 文档声明

    • 在XML文档的最前面,必须编写一个文档声明,用来声明XML文档的类型
      • 最简单的声明
    <?xml version="1.0" ?>
    
    • 用encoding属性说明文档的字符编码
    <?xml version="1.0" encoding="UTF-8" ?>
    

    2.1.2 XML语法 – 元素(Element)

    • 一个元素包括了开始标签和结束标签

      • 拥有内容的元素:<video>小黄人</video>
      • 没有内容的元素:<video></video>
      • 没有内容的元素简写:<video/>
    • 一个元素可以嵌套若干个子元素(不能出现交叉嵌套)

    <videos>
        <video>
            <name>小黄人 第01部</name>
              <length>30</length>
        </video>
    </videos>
    
    • 规范的XML文档最多只有1个根元素,其他元素都是根元素的子孙元素

    2.1.3 XML语法 –元素的注意

    • XML中的所有空格和换行,都会当做具体内容处理
    • 下面两个元素的内容是不一样的
      • 第1个
    <video>小黄人</video>
    
    • 第2个
    <video>
        小黄人
    </video>
    

    2.1.4 XML语法 – 属性(Attribute)

    • 一个元素可以拥有多个属性
    <video name="小黄人 第01部" length="30" />
    
    • video元素拥有name和length两个属性

    • 属性值必须用 双引号"" 或者 单引号'' 括住

    • 实际上,属性表示的信息也可以用子元素来表示,比如

    <video>
        <name>小黄人 第01部</name>
            <length>30</length>
    </video>
    

    2.1.5 XML解析

    • 要想从XML中提取有用的信息,必须得学会解析XML
      • 提取name元素里面的内容
    <name>小黄人 第01部</name>
    
    • 提取video元素中name和length属性的值
    <video name="小黄人 第01部" length="30" />
    
    • XML的解析方式有2种
      • DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
      • SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件

    2.1.6 iOS中的XML解析

    • 在iOS中,解析XML的手段有很多

      • 苹果原生

        • NSXMLParser:SAX方式解析,使用简单
      • 第三方框架

        • libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
        • GDataXML:DOM方式解析,由Google开发,基于libxml2
    • XML解析方式的选择建议

      • 大文件:NSXMLParser、libxml2
      • 小文件:GDataXML、NSXMLParser、libxml2

    2.1.7 NSXMLParser

    • 使用步骤
    // 传入XML数据,创建解析器
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
    // 设置代理,监听解析过程
    parser.delegate = self;
    // 开始解析,解析过程阻塞式的
    [parser parse];
    
    
    • NSXMLParser采取的是SAX方式解析,特点是事件驱动,下面情况都会通知代理
      • 当扫描到文档(Document)的开始与结束
      • 当扫描到元素(Element)的开始与结束

    2.1.8 NSXMLParserDelegate

    • 当扫描到文档的开始时调用(开始解析)
    - (void)parserDidStartDocument:(NSXMLParser *)parser
    
    • 当扫描到文档的结束时调用(解析完毕)
    - (void)parserDidEndDocument:(NSXMLParser *)parser
    
    • 当扫描到元素的开始时调用(attributeDict存放着元素的属性)
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
    
    • 当扫描到元素的结束时调用
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
    
    • 具体代码如下:
    #define SCREENWIDTH [UIScreen mainScreen].bounds.size.width
    #define SCREENHEIGHT [UIScreen mainScreen].bounds.size.height
    #import "ViewController.h"
    #import <MediaPlayer/MediaPlayer.h>
    
    #import "VideoModel.h"
    
    #import "UIImageView+WebCache.h"
    #import "MJExtension.h"
    
    //#define baseURLStr @"http://120.25.226.186:32812";
    static NSString *  baseURLStr = @"http://120.25.226.186:32812";
    
    @interface ViewController ()<UITableViewDelegate,UITableViewDataSource,NSXMLParserDelegate>
    
    @property (nonatomic,strong) UITableView * tableView;
    
    @property (nonatomic,strong) NSMutableArray * videoArray;
    
    @property (nonatomic,strong) VideoModel * videoModel;
    
    @end
    
    @implementation ViewController
    
    #pragma mark - lazyLoading
    -(UITableView *)tableView
    {
        if (!_tableView) {
            _tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, SCREENWIDTH, SCREENHEIGHT) style:UITableViewStylePlain];
            _tableView.delegate = self;
            _tableView.dataSource = self;
            _tableView.showsVerticalScrollIndicator = NO;
            // 没有分割线
            //        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
            
        }
        return _tableView;
    }
    
    #pragma mark - 可变数组懒加载
    -(NSMutableArray *)videoArray
    {
        if (!_videoArray) {
            _videoArray = [NSMutableArray array];
        }
        return _videoArray;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        [self NetWorkURL];
        
        [self.view addSubview:self.tableView];
    }
    
    #pragma mark - 设置多少个分组
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return 1;
    }
    
    #pragma mark - 设置分组里需要多少行
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.videoArray.count;
    }
    
    #pragma  mark - 设置分组每行的高度
    -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return 150;
    }
    
    
    #pragma mark - 填充tableview 各组各行的内容
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString * Identifier = @"CellID";
        
        UITableViewCell * cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:Identifier];
        
        if (cell == nil) {
            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:Identifier];
        }
        
        // 2.1 拿到该cell对应的数据
        //    NSDictionary * dicM = self.videoArray[indexPath.row];
        
        self.videoModel = self.videoArray[indexPath.row];
        
        // 2.2 设置标题
        cell.textLabel.text = self.videoModel.name;
        
        // 2.3 设置子标题
        cell.detailTextLabel.text = [NSString stringWithFormat:@"播放时间:%@",self.videoModel.length];
        
        //    NSString * baseURLStr = @"http://120.25.226.186:32812";
        NSString * urlStr = [baseURLStr stringByAppendingPathComponent:self.videoModel.image];
        
        // 2.4 设置图片
        [cell.imageView sd_setImageWithURL:[NSURL URLWithString:urlStr] placeholderImage:[UIImage imageNamed:@"home_forum_holder"]];
        
        NSLog(@"-----%@",self.videoModel.ID);
        
        //去掉底部多余的表格线
        [tableView setTableFooterView:[[UIView alloc] initWithFrame:CGRectZero]];
        
        return cell;
    }
    
    #pragma mark - 点击对应的 tableview 的效果
    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        
        // 1. 拿到数据
        //    NSDictionary * dic = self.videoArray[indexPath.row];
        
        self.videoModel = self.videoArray[indexPath.row];
        
        // 2. 拼接数据
        NSString * urlStr = [baseURLStr stringByAppendingPathComponent:self.videoModel.url];
        
        // 3. 创建播放器
        MPMoviePlayerViewController * videoPlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:urlStr]];
        
        // 4. 弹出控制器
        [self presentViewController:videoPlayer animated:YES completion:nil];
    }
    
    #pragma mark - 网络数据请求
    -(void)NetWorkURL
    {
        
        
        // 1. 确定URL
        NSURL * url = [NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"];
        // 2. 创建发送对象
        NSURLRequest * request = [NSURLRequest requestWithURL:url];
        // 3. 发送请求
        [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue]
                               completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
                                   
                                   if (connectionError) {
                                       return ;
                                   }
                                   
                                   
                                   // 4. 解析数据
                                   // 4.1 创建XML解析器:SAX
                                   NSXMLParser * parser = [[NSXMLParser alloc] initWithData:data];
                                   
                                   // 4.2 设置代理
                                   parser.delegate = self;
                                   
                                   // 4.3 开始解析,阻塞
                                   [parser parse];
                                   
                                   // 5. 更新UI
                                   [self.tableView reloadData];
                                   
                               }];
    }
    
    
    #pragma mark - NSXMLParserDelegate
    // 1. 开始解析XML文档的时候
    -(void)parserDidStartDocument:(NSXMLParser *)parser
    {
        NSLog(@"%s",__func__);
    }
    
    // 2. 开始解析某个元素
    -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict
    {
        NSLog(@"开始解析: %@-----%@",elementName,attributeDict);
        
        // 过滤根元素
        if ([elementName isEqualToString:@"videos"]) {
            return;
        }
        
        // 字典转模型
        [self.videoArray addObject:[VideoModel mj_objectWithKeyValues:attributeDict]];
    }
    
    // 3. 某个元素解析完毕
    -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
    {
        NSLog(@"结束解析: %@",elementName);
    }
    
    
    // 4. 结束解析
    -(void)parserDidEndDocument:(NSXMLParser *)parser
    {
        NSLog(@"%s",__func__);
    }
    @end
    

    相关文章

      网友评论

          本文标题:网络请求之JSON和XML

          本文链接:https://www.haomeiwen.com/subject/dgbgvxtx.html