JSON数据解析:
- JSON的简单介绍:
- 什么是JSON
 
- JSON以一种轻量级的数据格式,一般用来数据交互
 
- 服务器返回给客户端的数据一般都是JSON或者XML格式(问价下载除外)
 
- JSON相关说明
 
- JSON格式很想oc中的字典
 
- 标准JSON格式中的key必须是双引号
 
- 解析JSON的方案
 
- 第三方框架
 
- 苹果原生:NSJSONSerialization
 
 
- JSON解析相关代码
  //把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);
         }];
     }
  //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解析
  //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
```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实现大文件下载:
  //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"];
 
文件的压缩与解压缩
多值参数和中文输出
- 多值参数
   /*
  如果一个参数对应着多个值,那么直接按照"参数=值&参数=值"的方式拼接
  */
 -(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
           
网友评论