网络02

JSON数据解析:

  • JSON的简单介绍:
    • 什么是JSON
    • JSON以一种轻量级的数据格式,一般用来数据交互
    • 服务器返回给客户端的数据一般都是JSON或者XML格式(问价下载除外)
    • JSON相关说明
    • JSON格式很想oc中的字典
    • 标准JSON格式中的key必须是双引号
    • 解析JSON的方案
    • 第三方框架
    • 苹果原生:NSJSONSerialization
  • JSON解析相关代码
    • JSON数据->OC(反序列化)
      //把json数据转换为OC对象
         -(void)jsonToOC
         {
             //1. 确定url路径
             NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=33&pwd=33&type=JSON"];
    
             //2.创建一个请求对象
             NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
             //3.使用NSURLSession发送一个异步请求
             [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
    
                 //4.当接收到服务器响应的数据后,解析数据(JSON--->OC)
    
                 /*
                  第一个参数:要解析的JSON数据,是NSData类型也就是二进制数据
                  第二个参数: 解析JSON的可选配置参数
                  NSJSONReadingMutableContainers 解析出来的字典和数组是可变的
                  NSJSONReadingMutableLeaves 解析出来的对象中的字符串是可变的  iOS7以后有问题
                  NSJSONReadingAllowFragments 被解析的JSON数据如果既不是字典也不是数组, 那么就必须使用这个
                  */
                 NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
                 NSLog(@"%@",dict);
    
             }];
         }
    
    • OC对象->JSON对象
      //1.要转换成JSON数据的OC对象*这里是一个字典
            NSDictionary *dictM = @{
                                    @"name":@"wendingding",
                                    @"age":@100,
                                    @"height":@1.72
                                    };
            //2.OC->JSON
            /*
             注意:可以通过+ (BOOL)isValidJSONObject:(id)obj;方法判断当前OC对象能否转换为JSON数据
             具体限制:
                 1.obj 是NSArray 或 NSDictionay 以及他们派生出来的子类
                 2.obj 包含的所有对象是NSString,NSNumber,NSArray,NSDictionary 或NSNull
                 3.字典中所有的key必须是NSString类型的
                 4.NSNumber的对象不能是NaN或无穷大
             */
            /*
             第一个参数:要转换成JSON数据的OC对象,这里为一个字典
             第二个参数:NSJSONWritingPrettyPrinted对转换之后的JSON对象进行排版,无意义
             */
            NSData *data = [NSJSONSerialization dataWithJSONObject:dictM options:NSJSONWritingPrettyPrinted error:nil];
    
            //3.打印查看Data是否有值
            /*
             第一个参数:要转换为STring的二进制数据
             第二个参数:编码方式,通常采用NSUTF8StringEncoding
             */
            NSString *strM = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@",strM);
    
  • OC对象与JSON对象之间的一一对应关系
      //OC对象和JSON数据之间的一一对应关系
         -(void)oCWithJSON
         {
             //JSON的各种数据格式
             //NSString *test = @"\"wendingding\"";
             //NSString *test = @"true";
             NSString *test = @"{\"name\":\"wendingding\"}";
    
             //把JSON数据->OC对象,以便查看他们之间的一一对应关系
             //注意点:如何被解析的JSON数据如果既不是字典也不是数组(比如是NSString), 那么就必须使用这NSJSONReadingAllowFragments
             id obj = [NSJSONSerialization JSONObjectWithData:[test dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil];
    
             NSLog(@"%@", [obj class]);
             /* JSON数据格式和OC对象的一一对应关系
                  {} -> 字典
                  [] -> 数组
                  "" -> 字符串
                  10/10.1 -> NSNumber
                  true/false -> NSNumber
                  null -> NSNull
              */
         }
         }
    
  • 如何查看复杂的JSON数据
    ```objc
     [dictM writeToFile:@"/Users/文顶顶/Desktop/videos.plist" atomically:YES];
     ```
    
  • 视频的简单播放
      //0.需要导入系统框架
     #import <MediaPlayer/MediaPlayer.h>
    
     //1.拿到该cell对应的数据字典
     XMGVideo *video = self.videos[indexPath.row];
    
     NSString *videoStr = [@"http://120.25.226.186:32812" stringByAppendingPathComponent:video.url];
    
     //2.创建一个视频播放器
     MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString:videoStr]];
     //3.present播放控制器
    
     [self presentViewController:vc animated:YES completion:nil];
    
  • MJExtension
  • 简单使用
```objc
  //1.把字典数组转换为模型数组
        //使用MJExtension框架进行字典转模型
            self.videos = [XMGVideo mj_objectArrayWithKeyValuesArray:videoArray];

    //2.重命名模型属性的名称
    //第一种重命名属性名称的方法,有一定的代码侵入性
    //设置字典中的id被模型中的ID替换
    +(NSDictionary *)mj_replacedKeyFromPropertyName
    {
        return @{
                 @"ID":@"id"
                 };
    }

    //第二种重命名属性名称的方法,代码侵入性为零
        [XMGVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
            return @{
                     @"ID":@"id"
                     };
        }];

    //3.MJExtension框架内部实现原理-运行时
```

XML解析

  • XML解析
  • 使用XMLParser
  //1.发送请求
 [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

     //2.解析数据
     //2.1 创建XML解析器
     NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];

     //2.2 设置代理
     parser.delegate = self;

     //2.3 开始解析,该方法本身是阻塞的
     [parser parse];

     //4.刷新tableView
     dispatch_async(dispatch_get_main_queue(), ^{
          [self.tableView reloadData];
     });
 }] resume];

 //1.开始解析XML文档
     -(void)parserDidStartDocument:(nonnull NSXMLParser *)parser

     //2.开始解析XML中某个元素的时候调用,比如<video>
     -(void)parser:(nonnull NSXMLParser *)parser didStartElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(nonnull NSDictionary<NSString *,NSString *> *)attributeDict
     {
         if ([elementName isEqualToString:@"videos"]) {
             return;
         }
         //字典转模型
         XMGVideo *video = [XMGVideo objectWithKeyValues:attributeDict];
         [self.videos addObject:video];
     }

     //3.当某个元素解析完成之后调用,比如</video>
     -(void)parser:(nonnull NSXMLParser *)parser didEndElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName

     //4.XML文档解析结束
     -(void)parserDidEndDocument:(nonnull NSXMLParser *)parser
  • MJExtension使用小技巧
```objc
//0.告诉框架新值和旧值的对应关系
[XMGVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
    return @{
             @"ID":@"id",
             };

}];
```
  • NSURLSessionDownloadTask大文件下载
  • NSURLSessionDownloadTask实现大文件下载-Block
  • 使用URLSession和URLSessionDownload可以很方便的实现文件下载
  ```objc
    1)使用NSURLSession和NSURLSessionDownload可以很方便的实现文件下载操作
 /*
     第一个参数:要下载文件的url路径
     第二个参数:当接收完服务器返回的数据之后调用该block
     location:下载的文件的保存地址(默认是存储在沙盒中tmp文件夹下面,随时会被删除)
     response:服务器响应信息,响应头
     error:该请求的错误信息
     */
    //说明:downloadTaskWithURL方法已经实现了在下载文件数据的过程中边下载文件数据,边写入到沙盒文件的操作
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:url completionHandler:^(NSURL * __nullable location, NSURLResponse * __nullable response, NSError * __nullable error)
  ```
-  downloadTaskWithURL内部已经实现了边下载边写入操作,所以开发人员不必担心内存问题
- 文件下载后默认保存到tmp目录,需要手动剪切到指定的沙盒目录
- 缺点:无法监听下载进度
  • 使用NSURLSessionDownloadTask实现大文件下载-代理
  • 创建NSURLSession并设置代理,通过NSURLSessionDownloadTask并以代理的方式实现大文件的下载
      //1.创建NSULRSession,设置代理
      self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    
      //2.创建task
      NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
      self.downloadTask = [self.session downloadTaskWithURL:url];
    
      //3.执行task
      [self.downloadTask resume];
    
  • 常用代理方法说明
  ```objc
      /*
     1.当接收到下载数据的时候调用,可以在该方法中监听文件下载的进度
     该方法会被调用多次
     totalBytesWritten:已经写入到文件中的数据大小
     totalBytesExpectedToWrite:目前文件的总大小
     bytesWritten:本次下载的文件数据大小
     */
    -(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
    /*
     2.恢复下载的时候调用该方法
     fileOffset:恢复之后,要从文件的什么地方开发下载
     expectedTotalBytes:该文件数据的总大小
     */
    -(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
    /*
     3.下载完成之后调用该方法
     */
    -(void)URLSession:(nonnull NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location
    /*
     4.请求完成之后调用
     如果请求失败,那么error有值
     */
    -(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error
  ```
-  实现断点下载相关代码:
  ```objc
    //如果任务,取消了那么以后就不能恢复了
    //    [self.downloadTask cancel];

    //如果采取这种方式来取消任务,那么该方法会通过resumeData保存当前文件的下载信息
    //只要有了这份信息,以后就可以通过这些信息来恢复下载
    [self.downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {
        self.resumeData = resumeData;
    }];

    -----------
    //继续下载
    //首先通过之前保存的resumeData信息,创建一个下载任务
    self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];

     [self.downloadTask resume];
  ```
-  计算当前下载进度
  ```objc
     //获取文件下载进度
    self.progress.progress = 1.0 * totalBytesWritten/totalBytesExpectedToWrite;
  ```
-  局限性:
  ```objc
    01 如果用户点击暂停之后退出程序,那么需要把恢复下载的数据写一份到沙盒,代码复杂度更
    02 如果用户在下载中途未保存恢复下载数据即退出程序,则不具备可操作性
  ```
  • NSURLSessionDataTask实现大文件下载:
    • 关于NSOutputStream的使用
      //1. 创建一个输入流,数据追加到文件的屁股上
     //把数据写入到指定的文件地址,如果当前文件不存在,则会自动创建
    NSOutputStream *stream = [[NSOutputStream alloc]initWithURL:[NSURL fileURLWithPath:[self fullPath]] append:YES];
    
      //2. 打开流
    [stream open];
    
      //3. 写入流数据
    [stream write:data.bytes maxLength:data.length];
    
     //4.当不需要的时候应该关闭流
    [stream close];
    
    • 关于网络请求头的设置(可以设置指定下载某一部分文件)
      //1. 设置请求对象
      //1.1 创建请求路径
      NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
    
       //1.2 创建可变请求对象
      NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
       //1.3 拿到当前文件的残留数据大小
      self.currentContentLength = [self FileSize];
    
       //1.4 告诉服务器从哪个地方开始下载文件数据
       NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentContentLength];
      NSLog(@"%@",range);
    
      //1.5 设置请求头
      [request setValue:range forHTTPHeaderField:@"Range"];
    
    • NSURLSession对象的释放
            -(void)dealloc
          {
             //在最后的时候应该把session释放,以免造成内存泄露
            //    NSURLSession设置过代理后,需要在最后(比如控制器销毁的时候)调用session的invalidateAndCancel或者resetWithCompletionHandler,才不会有内存泄露
            //    [self.session invalidateAndCancel];
           [self.session resetWithCompletionHandler:^{
      
            NSLog(@"释放---");
           }];
          }
      

文件的压缩与解压缩

  • 说明:
  • 使用ZipArchive来压缩和解压缩文件需要添加依赖库(libz),使用需要包含SSZipArchive文件,如果使用cocoaPoads来安装框架,那么会自动的配置框架的使用环境
  • 相关代码实现:
      //压缩文件的第一种方式
         /*
          第一个参数:压缩文件要保存的位置
          第二个参数:要压缩哪几个文件
          */
         [SSZipArchive createZipFileAtPath:fullpath withFilesAtPaths:arrayM];
    
         //压缩文件的第二种方式
         /*
          第一个参数:文件压缩到哪个地方
          第二个参数:要压缩文件的全路径
          */
         [SSZipArchive createZipFileAtPath:fullpath withContentsOfDirectory:zipFile];
    
         //如何对压缩文件进行解压
         /*
          第一个参数:要解压的文件
          第二个参数:要解压到什么地方
          */
         [SSZipArchive unzipFileAtPath:unZipFile toDestination:fullpath];
    

多值参数和中文输出

  • 多值参数
       /*
      如果一个参数对应着多个值,那么直接按照"参数=值&参数=值"的方式拼接
      */
     -(void)test
     {
         //1.确定URL
         NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/weather?place=Beijing&place=Guangzhou"];
         //2.创建请求对象
         NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
         //3.发送请求
         [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
    
             //4.解析
             NSLog(@"%@",[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
         }];
     }
    
    
  • 如何解决字典或者数组输出乱码的问题
  给字典和数组添加一个分类,重写descriptionWithLocale方法,在该方法中拼接元素格式化输出。
  -(nonnull NSString *)descriptionWithLocale:(nullable id)locale
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容