zoukankan      html  css  js  c++  java
  • 玩转iOS开发

    前言

    Json 和xml是网络开发中经常使用的数据格式,JSON轻量级。xml相对较复杂。所以如今用JSON的比例很大。基本上从server获取的返回数据都是JSON格式的,作为iOS开发人员,解析JSON, XML文件是网络开发最主要的一步,不扯蛋了,直接进入正题。

    JSON解析

    JSON介绍

    JSON 本质上,就是一个”特殊格式”的字符串

    • JSON 是网络上用来数据传输使用最广泛的数据格式,没有之中的一个
    • JSON 出身草根,是 Javascript 的子集,专门负责描写叙述数据格式

    參考站点:http://www.w3cschool.cc

    JSON 语法规则

    • 数据以 key/value 值对表示
    • 数据由逗号分隔
    • 花括号保存对象 (字典)
    • 方括号保存数组

    JSON 存储值

    • 数字(整数或浮点数)
    • 字符串(在双引號中)
    • 逻辑值(true 或 false)
    • 数组(在方括号里)
    • 对象(在花括号里)
    • null

    以下看条结构清晰的JSON数据,和上面JSON的特点相应一下:

    这里写图片描写叙述

    序列化 & 反序列化

    • 序列化:在向server发送数据之前,将 NSArray / NSDictionary 转换成二进制的过程
    • 反序列化:在从server接收到数据之后。将二进制数据转换成 NSArray / NSDictionary 的过程

    JSON 反序列化

    • 虎嗅新闻接口
    NSURL *url = [NSURL URLWithString:@"http://m.api.huxiu.com/portal/1/1?

    client_ver=6&push_type=iOSRel"];

    //反序列化
    id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
    选项 说明
    NSJSONReadingMutableContainers = (1UL << 0) 容器可变
    NSJSONReadingMutableLeaves = (1UL << 1) 叶子可变
    NSJSONReadingAllowFragments = (1UL << 2) 顶级节点能够不是 NSArray 或者 NSDictionary
    • 在实际开发中。获得网络的数组或者字典之后,一般会做字典转模型!

      反序列化的结果是否可变并不重要

    选项选择 0,表示不论什么附加操作都不做,效率最高!

    NSJSONSerialization 类

    • 专门负责在 JSON 和 Foundation 对象直接转换的类

    能够转换成 JSON 的 Foundation 对象须要具备的条件:

    * 顶级节点是 NSArray 或者 NSDictionary
    * 全部的对象是 NSString, NSNumber, NSArray, NSDictionary 或者 NSNull
    * 全部字典的 key 是 NSString
    * NSNumber 不是空或者无穷大
    

    JSON解析样例

    以下是一个简单的虎嗅新闻的样例:

    我们先来看下URL实际返回的JSON是什么样子的:
    这里写图片描写叙述

    在线 JSON解析的站点:http://json.cn

    演示样例代码用swift 写的。亲们看下Swift 代码是不是比OC美丽多了。而且今年swift2.0就要开源了喽,博主难以掩饰对swift的喜爱。哈哈

    有木有发现swift的代码使用起来和OC很像,使用函数的名字基本一致。仅仅只是那个讨厌的 [] 变成了让人喜爱的 . 语法,大爱。
    假设对swift感兴趣,能够兴许看下blog中swift系列的文章

    好了言归正传,亲们看下以下的JSON解析是不是很easy:

    func readJson() 
    {
        //这个是虎嗅新闻看点的API
        let url = NSURL(string: "http://m.api.huxiu.com/portal/1/1?client_ver=6&push_type=iOSRel")!
        let request = NSURLRequest(URL: url)
    
        //用NSURLConnection 做异步请求
        NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { (_, data, error) -> Void in
            if (data == nil || error != nil) 
            {
                println("网络不给力")
                return
            }
    
            //依据数据格式能够知道返回的是一个字典(有的站点会返回数组,比較少见)    
            let resultDic = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: nil) as! NSDictionary
    
            //获取内容部分,内容的key-> 'content', value:是个数组
            let resultArray = resultDic["content"] as! NSArray
    
            //这里我们仅仅看第一条新闻。也能够遍历数组查看全部的内容        
            let result = resultArray[0] as! NSDictionary;
    
            //依据key 提取我们想要的内容   
            let cityName = result["img"] as! String
            let author = result["author"] as! String
            let title = result["title"] as! String
            let summary = result["summary"] as! String
    
            println("虎嗅新闻 
    作者:(author)
    标题:(title) 
    摘要:(summary) ")
       }
    }

    上面结果输出:

    虎嗅新闻
    作者:虎嗅
    标题:综艺节目大爆炸。电视台和视频站点过得好吗
    摘要:要赚钱,还要领导放心,观众惬意,可真够难的。

    来看下手机app上的结果。是不是一样滴:

    这里写图片描写叙述

    注意:

    上面请求使用的swift 闭包{ (_, data, error) -> Void in} 来进行JSON数据解析,代码运行的顺序为:readJson函数-> 网络异步请求-> readJson 函数运行完毕-> server返回Json数据-> 回调闭包中代码块进行JSon数据解析。看吧,闭包和OC的block很想吧。实际上swift闭包功能更强大。

    JSON解析-第三方框架

    常见的 JSON 解析第三方框架

    • JSONKit(最快)
    • SBJson
    • TouchJSON

    上面三个框架的性能依次减少。所以我们仅仅说一下JSONKit

    JSONKit

    使用步骤步骤

    1. 下载框架 https://github.com/johnezang/JSONKit

    2. 导入框架文件

      • JSONKit.h
      • JSONKit.m
    3. 设置 MRC 标记(JSONKit 基于MRC的)

      • 选择”项目”-”Build Phases”-”Compile Sources”
      • 找到 JSONKit.m 而且在 Compiler Flags 中加入 -fno-objc-arc。 能够告诉编译器,编译 JSONKit.m 时不使用 ARC
    4. 改动错误

      • 利用自己主动修复功能。改动两处 isa 的错误
    5. 反序列化
      使用起来很easy。创建一个decoder对象,调用解析方法就能够

    id result = [[JSONDecoder decoder] objectWithData:data];

    注意

    • JSONKit 仅仅支持iOS5.0之前的系统,是MRC下的框架。所以新项目不要使用

    • JSONKit 2012已经停止更新。当时apple官方说JSONKit 的效率要高于系统自带的JSON解析,只是要知道苹果对于自身系统的优化更新是很快的,眼下的apple原生态的JSON解析已经完爆JSONKit了。假设你如今还在用他,建议换成系统自身的JSON解析。

    • 苹果新系统强制推广的速度很快。随着更新,许多以前的东西会被更好的替代,NSURLConnection 就是一个样例。所以程序员要跟上时代的潮流啊

    XML解析

    XML 介绍

    • XML的特点,出身名门,W3C制定,微软和IBM以前共同大力推荐过的数据格式
    • XML 指可扩展标记语言(eXtensible Markup Language)
    • 被设计用来传输和存储数据

    让我来看下XML数据,瞬间有木有想感觉信息量好大:

    <?xml version="1.0" encoding="UTF-8"?

    > <Books> <Book id="1"> <title>Circumference</title> <author>Nicholas Nicastro</author> <summary>Eratosthenes and the Ancient</summary> </Book> <Book id="2"> <title>Copernicus Secret</title> <author>Jack Repcheck</author> <summary>How the scientific revolution began</summary> </Book> <Book id="3"> <title>Angels and Demons</title> <author>Dan Brown</author> <summary>Robert Langdon is summoned to a Swiss</summary> </Book> </Books>

    XML 解析的方式

    DOM 解析

    • 是在 MAC上使用的解析方式
    • 内存消耗极大,不适用于手机
    • iPhone无法直接使用 DOM 方式解析 XML

    SAX 解析

    • 是仅仅读的方式,从上向下的方式解析
    • 是苹果提供的解析方式
    • 速度快
    • NSXMLParser 通过代理实现解析

    SAX 解析步骤

    1. 開始文档 - 准备工作
    2. 開始”节点”
    3. 发现节点内部的内容。每个节点,可能须要多次才干找完
    4. 结束”节点”
    5. 结束文档 - 解析结束

    以上步骤,2。3。4。会不断循环,一直到全部解析完毕!

    事实上解析本质上就是不断循环遍历节点,获取节点内容。由于XML的节点格式是成对出现的。只是节点的名字是自己定义的,这也是解析难点所在。

    1. loadData

    - (void)loadData {
    
        NSURL *url = [NSURL URLWithString:@"http://localhost/books.xml"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
        // 异步解析 XML
        [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    
            // 1. 使用网络返回的二进制数据实例化 NSXMLParser 对象
            NSXMLParser *ZHParser = [[NSXMLParser alloc] initWithData:data];
    
            // 2. 设置代理,通过代理方法实现 SAX 解析
            ZHParser.delegate = self;
    
            // 3. 開始解析
            [ZHParser parse];
        }];
    }

    使用代理方法获取数据

    仅仅要没有碰到文档的结束符。解析器就会循化运行2,3,4方法,直到所以后的数据解析完

    // MARK: - NSXMLParserDelegate
    // 1. 開始文档 - 准备工作
    - (void)parserDidStartDocument:(NSXMLParser *)parser {
        NSLog(@"1. 開始文档");
    }
    
    // 2. 開始节点
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
        NSLog(@"2. 開始节点 %@ %@", elementName, attributeDict);
    }
    
    // 3. 发现文字
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
        NSLog(@"==> %@", string);
    }
    
    // 4. 结束节点
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
        NSLog(@"4. 结束节点 %@", elementName);
    }
    // 5. 结束文档 - 解析结束
    - (void)parserDidEndDocument:(NSXMLParser *)parser {
        NSLog(@"5. 解析结束");
    }
    
    // 6. 错误处理
    - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
        NSLog(@"解析错误 %@", parseError);
    }

    SAX & DOM 解析对照

    SAX 特点

    • 仅仅读
    • 从上向下
    • 速度快
    • 解析的时候相对照较繁琐,有5个代理方法。每个代理方法都要写一定代码
    • 适合大的 XML 文件解析

    总的来说。SAX仅仅在xml文档中查找特定条件的内容。而且仅仅提取须要的内容。这样做占用内存小,灵活。

    DOM 特点

    • 背景

      • 主要用在 PC 端或者server端
      • 苹果提供了 NSXML 类支持 DOM 方式的解析
      • 只是 NSXML 类仅仅能用在 MAC 开发。在 iOS 中无法直接使用
      • DOM 方式不仅能解析 XML 文档,还能够改动: 添加节点/删除节点
    • 实现

      • 一次性将 XML 文档以树形结构读入内存
      • 横向的节点越多,内存消耗越大
      • 使用 DOM 解析适合于小的 XML 解析,而且能够动态维护
      • 有些第三方框架就提供了 DOM 方式的解析,GDataKissXML(XMPP)
      • 在 iOS 开发中,假设要使用 DOM 方式解析,最好仅仅处理小的 XML

    GData解析XML

    GDataXMLNode是Google提供的用于XML数据处理的类集。该类集对libxml2-DOM处理方式进行了封装,能对较小或中等的XML文档进行读写操作且支持XPath语法。 原理上和DOM同样。

    GData解析步骤

    • 获得根节点。依次 Log,一定要确认能够拿到全部子节点的内容
    • 横向节点越多,for的层次就越深
    • 依据实际的 XML 的情况,确认解析

    准备工作

    GData使用演示样例

    XML数据

    <?xml version="1.0"?>
    <xml_api_reply version="1">
    <cities>
    <city>
    <name data="保定"/>
    <latitude_e6> 38849998</latitude_e6>
    <longitude_e6> 115569999</longitude_e6>
    </city>
    <city default="true" >
    <name data="北京"/>
    <latitude_e6> 39930000</latitude_e6>
    <longitude_e6> 116279998</longitude_e6>
    </city>
    <city>
    <name data="沈阳"/>
    <latitude_e6> 41770000</latitude_e6>
    <longitude_e6> 123430000</longitude_e6>
    </city>
    <city>
    <name data="成都"/>
    <latitude_e6> 30670000</latitude_e6>
    <longitude_e6> 104019996</longitude_e6>
    </city>
    <city>
    <name data="大连"/>
    <latitude_e6> 38900001</latitude_e6>
    <longitude_e6> 121629997</longitude_e6>
    </city>
    <city>
    <name data="福州"/>
    <latitude_e6> 26079999</latitude_e6>
    <longitude_e6> 119279998</longitude_e6>
    </city>
    </cities>
    </xml_api_reply>

    解析方法

    首先分析下数据层次结构:

    <?

    xml version="1.0"?> : </xml_api_reply> <cities> : </cities> <city> : </city>

    依据上面的节点来解析数据。要有两个for循环

    - (void)parseCitys
    {
        NSData *xmlCitysData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"citys" ofType:@"xml"]];
    
        // 读取data在内存中形成完整的树形结构
        NSError * error = nil;
        GDataXMLDocument * documents = [[GDataXMLDocument alloc]initWithData:xmlCitysData options:0 error:&error];
    
        // 取得根节点
        GDataXMLElement *rootNode = [documents rootElement];
    
        //获取根节点xml_api_reply的数组,包括的是cities,假设根节点不知有一个数组。就又要遍历
        NSArray * citiesArray = [rootNode elementsForName:@"cities"];
        for (int i = 0; i < [citiesArray count]; i++) {
    
            // 取得单个cities节点
            GDataXMLElement * cities = [citiesArray objectAtIndex:i];
    
            //获取节点cities的数组,包括的是city
            //看出规律了吧,通过当前GDataXMLElement和子节点的name,能够获取子节点的数组
            NSArray * cityArray = [cities elementsForName:@"city"];
            for (int j = 0; j < [cityArray count]; j++) {
    
                // 取得单个city节点
                GDataXMLElement * city = [cityArray objectAtIndex:j];
    
                //节点以下是3个并行的节点,都是1个,直接通过lastObject来取得想要的值
                NSString * name = [[[[city elementsForName:@"name"]lastObject] attributeForName:@"data"] stringValue];
                NSLog(@"name = %@",name);
    
                NSString * latitude_e6 = [[[city elementsForName:@"latitude_e6"]lastObject] stringValue];
                NSLog(@"latitude_e6 = %@",latitude_e6);
    
                NSString * longitude_e6 = [[[city elementsForName:@"longitude_e6"]lastObject] stringValue];
                NSLog(@"longitude_e6 = %@",longitude_e6);   
            }       
        }   
    }

    PList解析

    PList 主要在苹果开发中经常使用。比方那个新建项目都会自带一个info.plist,事实上全部的数据格式都是相通的,无非存储数组。字典。对象,好的数据格式就是易于存储,易于读写。

    这里最后简介下plist, 毕竟大部分server后台并不会返回 PList 的数据格式。

    /**
     參数
     1. data:   要反序列化的二进制数据
     2. option: 选项,位移枚举类型
         NSPropertyListImmutable = 0,                   不可变
         NSPropertyListMutableContainers = 1,           容器可变
         NSPropertyListMutableContainersAndLeaves = 2   容器和叶子可变
     3. format: 假设不希望知道格式。传入 NULL 就可以
     4. error:  错误
     */
    id result = [NSPropertyListSerialization propertyListWithData:data options:0 format:NULL error:NULL];

    兴许阅读

  • 相关阅读:
    自动支持图片webp格式压缩,图片服务器升级webserver
    长江商学院介绍及名人校友名单
    恒大许家印靠斗着地主,当上首富
    用GitLab搭建自己的私有GitHub
    vim快速定位到某一行的几种方法和显示行号,定位匹配字符串,显示当前行信息的命令
    mysql数据库表上百万记录优化思路杂谈
    Java打印输出数组的三种方式:传统的for循环方式,for each循环,利用Arrays类中的toString方法
    个人快速成长之系统方法,最小化成长系统
    程序员应该了解的常见软件开发定律
    用python修改文件内容修改txt内容的3种方法
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5224315.html
Copyright © 2011-2022 走看看