美文网首页我爱编程
基本JSON, XML解析,和大文件下载压缩

基本JSON, XML解析,和大文件下载压缩

作者: _心暖 | 来源:发表于2016-04-22 19:53 被阅读445次

    1 JSON简单介绍
    1) 什么是JSON
    (1)JSON是一种轻量级的数据格式,一般用于数据交互
    (2)服务器返回给客户端的数据,一般都是JSON格式或者XML格式(文件下载除外)
    2) 相关说明
    (1)JSON的格式很像OC中的字典和数组
    (2)标准JSON格式key必须是双引号
    3)JSON解析方案
    a.第三方框架 JSONKit\SBJSON\TouchJSON
    b.苹果原生(NSJSONSerialization)

    2 JSON解析相关代码
    1)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);
    
            }];
        }
    
    2)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);
    
    3)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
             */
        }
        }
    4)如何查看复杂的JSON数据
    方法一:
        在线格式化http://tool.oschina.net/codeformat/json
    方法二:
        把解析后的数据写plist文件,通过plist文件可以直观的查看JSON的层次结构。
        [dictM writeToFile:@"/Users/文顶顶/Desktop/videos.plist" atomically:YES];
    
    5)视频的简单播放
    //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];
    

    3 字典转模型框架
    1)相关框架
    a.Mantle 需要继承自MTModel
    b.JSONModel 需要继承自JSONModel
    c.MJExtension 不需要继承,无代码侵入性

    2)自己设计和选择框架时需要注意的问题
        a.侵入性
        b.易用性,是否容易上手
        c.扩展性,很容易给这个框架增加新的功能
    
    3)MJExtension框架的简单使用
        //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框架内部实现原理-运行时
    

    =======================================================================================================

    2 XML解析

    1 XML简单介绍
    1) XML:可扩展标记语言
    a.语法
    b.XML文档的三部分(声明、元素和属性)
    c.其它注意点(注意不能交叉包含、空行换行、XML文档只能有一个根元素等)

    2) XML解析
    
        a.XML解析的两种方式
            001 SAX:从根元素开始,按顺序一个元素一个元素的往下解析,可用于解析大、小文件
            002 DOM:一次性将整个XML文档加载到内存中,适合较小的文件
        b.解析XML的工具
            001 苹果原生NSXMLParser:使用SAX方式解析,使用简单
            002 第三方框架
                libxml2:纯C语言的,默认包含在iOS SDK中,同时支持DOM和SAX的方式解析
                GDataXML:采用DOM方式解析,该框架由Goole开发,是基于xml2的
    

    2 XML解析
    1)使用NSXMLParser解析XML步骤和代理方法
    //解析步骤:
    //4.1 创建一个解析器
    NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
    //4.2 设置代理
    parser.delegate = self;
    //4.3 开始解析
    [parser parse];


        //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
    
    
    2)使用GDataParser解析XML的步骤和方法
        //  0 配置环境
        // 001 先导入框架,然后按照框架使用注释配置环境
        // 002 GDataXML框架是MRC的,所以还需要告诉编译器以MRC的方式处理GDataXML的代码
    
        //  1 加载XML文档(使用的是DOM的方式一口气把整个XML文档都吞下)
            GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:data options:kNilOptions error:nil];
    
        //  2 获取XML文档的根元素,根据根元素取出XML中的每个子元素
          NSArray * elements = [doc.rootElement elementsForName:@"video"];
    
        //  3 取出每个子元素的属性并转换为模型
        for (GDataXMLElement *ele in elements) {
    
            XMGVideo *video = [[XMGVideo alloc]init];
            video.name = [ele attributeForName:@"name"].stringValue;
            video.length = [ele attributeForName:@"length"].stringValue.integerValue;
            video.url = [ele attributeForName:@"url"].stringValue;
            video.image = [ele attributeForName:@"image"].stringValue;
            video.ID = [ele attributeForName:@"id"].stringValue;
    
            //  4 把转换好的模型添加到tableView的数据源self.videos数组中
            [self.videos addObject:video];
        }
    

    =======================================================================================================

    3 NSURLSessionDownloadTask大文件下载

    1 NSURLSessionDownloadTask实现大文件下载-Block

    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)
    2)downloadTaskWithURL内部默认已经实现了变下载边写入操作,所以不用开发人员担心内存问题
    3)文件下载后默认保存在tmp文件目录,需要开发人员手动的剪切到合适的沙盒目录
    4)缺点:没有办法监控下载进度
    

    2 使用NSURLSessionDownloadTask实现大文件下载-代理
    1)创建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];
    
    2)常用代理方法的说明
            /*
         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
    
    3)实现断点下载相关代码
        //如果任务,取消了那么以后就不能恢复了
        //    [self.downloadTask cancel];
    
        //如果采取这种方式来取消任务,那么该方法会通过resumeData保存当前文件的下载信息
        //只要有了这份信息,以后就可以通过这些信息来恢复下载
        [self.downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {
            self.resumeData = resumeData;
        }];
    
        -----------
        //继续下载
        //首先通过之前保存的resumeData信息,创建一个下载任务
        self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
    
         [self.downloadTask resume];
    
    4)计算当前下载进度
        //获取文件下载进度
        self.progress.progress = 1.0 * totalBytesWritten/totalBytesExpectedToWrite;
    
    5)局限性
        01 如果用户点击暂停之后退出程序,那么需要把恢复下载的数据写一份到沙盒,代码复杂度更
        02 如果用户在下载中途未保存恢复下载数据即退出程序,则不具备可操作性
    

    =======================================================================================================

    4 NSURLSessionDataTask实现大文件下载

    1 关于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];
    

    2 关于网络请求请求头的设置(可以设置请求下载文件的某一部分)
    //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"];
    

    3 NSURLSession对象的释放
    -(void)dealloc
    {
    //在最后的时候应该把session释放,以免造成内存泄露
    // NSURLSession设置过代理后,需要在最后(比如控制器销毁的时候)调用session的invalidateAndCancel或者resetWithCompletionHandler,才不会有内存泄露
    // [self.session invalidateAndCancel];
    [self.session resetWithCompletionHandler:^{

            NSLog(@"释放---");
        }];
    }
    

    4 优化部分

        01 关于文件下载进度的实时更新
        02 方法的独立与抽取
    

    =======================================================================================================

    5 文件压缩和解压缩

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

    =======================================================================================================

    6 多值参数和中文输出

    1 多值参数
    /*
    如果一个参数对应着多个值,那么直接按照"参数=值&参数=值"的方式拼接
    */
    -(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]);
        }];
    }
    

    2 如何解决字典和数组中输出乱码的问题
    给字典和数组添加一个分类,重写descriptionWithLocale方法,在该方法中拼接元素格式化输出。
    -(nonnull NSString *)descriptionWithLocale:(nullable id)locale

    相关文章

      网友评论

        本文标题: 基本JSON, XML解析,和大文件下载压缩

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