Fork me on GitHub

第十五讲.数据解析(XML与JSON两种数据解析),以及单例的创建

一.解析的概念

    所谓“解析”:从事先规定好的格式中提取数据解析的前提:提前约定好格式、数据提供方按照格式提供数据、
    数据获取方则按照格式获取数据iOS开发常见的解析:XML解析、JSON解析

二.XML数据解析

  1.SAX:Simple API for XML。基于事件驱动的解析方式,逐行解析数据。(采用协议回调机制) 

  2.XML数据结构的语法

    声明:节点使用一对标签表示。起始和结束标签。
     根节点是起始节点,只有一个。节点可以嵌套。
     节点可以有值。存储在一对儿标签中。

 

 
   3.进行XML解析时使用到的SAX工具(NSXMLParser解析此为XML自带的解析工具)
     1>.SAX:Simple API for XML。基于事件驱动的解析方式,逐行解析数据。(采用协议回调机制) 
       1>.NSXMLParser是iOS自带的XML解析类。采用SAX方式解析数据。
       2>.解析过程由NSXMLParserDelegate协议方法回调
       3>.解析过程:开始标签->取值->结束标签->取值

     2>.SAX
 使用OC的类完成解析的目的,是逐行解析的,当解析到跟节点的结束标识的时候,结束解析。缺点:解析的慢,不是特别准确。使用的代理方法去解析。
 
 
NSXMLParser的解析方法:

 

  1 #import "ViewController.h"
  2 #import "Model.h"
  3 
  4 @interface ViewController ()<NSXMLParserDelegate>
  5 
  6 @property(nonatomic,strong)UITableView *tableView;
  7 
  8 @property(nonatomic,copy)NSString *string;
  9 
 10 @property(nonatomic,strong)NSMutableArray *dataArray;
 11 
 12 @end
 13 
 14 @implementation ViewController
 15 
 16 - (void)viewDidLoad {
 17     [super viewDidLoad];
 18     // Do any additional setup after loading the view.
 19 
 20     
 21     
 22 }
 23 
 24 
 25 //NSXMLParser类的数据解析***************************************
 26 //以数字开头是,分两段解析
 27 - (IBAction)SAXSlution:(UIButton *)sender {
 28     
 29     //XML数据解析  第一步  获取相应的文件  转化为NSString类型
 30     //如果需要取得的文件在左边栏里,需要使用NSBundle类,获取路径
 31     //第一个参数代表文件的名字,可以连着类型
 32     //第二个参数代表文件类型 如果第一个有参数 第二个为空
 33     //@"date.txt" 名字要注意
 34     NSString *patarStr = [[NSBundle mainBundle] pathForResource:@"date.txt" ofType:nil];
 35     
 36     //第二步将转化成的字符串类型   转化为data类型
 37     
 38     //通过patarStr这个路径拿到文件,  转化成data
 39     //NSDate 代表的是时间,    NSData    代表的是数据
 40     NSData *data = [NSData dataWithContentsOfFile:patarStr];
 41     
 42     //第三步  转化为data类型那个的数据,使用NSXMLParser方法进行解析
 43     
 44     //系统提供的  XML解析类
 45     NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
 46     
 47     //指定代理
 48     parser.delegate = self;
 49     
 50     //开始解析文档
 51     [parser parse];
 52     
 53 }
 54 
 55 #pragma -mark   NSXMLParserDelegate
 56 
 57 //开始解析文档
 58 -(void)parserDidStartDocument:(NSXMLParser *)parser
 59 {
 60     //在这里初始化数组
 61     //因为只走一次,代表真正的解析的开始,所以数据源初始化放在这里进行
 62   self.dataArray  = [NSMutableArray array];
 63     
 64     NSLog(@"开始解析文档");
 65 }
 66 
 67 
 68 //开始解析标签  结束标签不打印(注意)   这里并没有打印出真正的内容,是开始解析的标志
 69 //第一个的参数代表的是标签的名字
 70 //第二个参数代表的是结点前面的修饰
 71 //第三个参数暂时不用
 72 //第四个参数代表的是标签的属性
 73 
 74 -(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
 75 {
 76     NSLog(@"%@",elementName);
 77     //在检测时           初始化一个model,
 78     if ([elementName isEqualToString:@"message"]) {
 79         Model *model = [[Model alloc] init];
 80         [self.dataArray addObject:model];
 81     }
 82 }
 83 
 84 //将解析的数据用字符串输出
 85 -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
 86 {
 87     NSLog(@"%@",string);
 88 //    Model *model = self.dataArray.lastObject;
 89     
 90     //这里拿不到标签,  只做保存数据的事情
 91 //    _string = string;
 92     
 93     //XML在解析时,数字在前时会解析成两段,可以用拼接的方法将他们连接在一起
 94     //拼接字符串,可以将分开的时间,也拼接在一起
 95     _string = [NSString stringWithFormat:@"%@ %@",_string,string];
 96     
 97 }
 98 
 99 //此为结束 解析 标签  (解析结束后就可以获得真正的值)
100 -(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
101 {
102     NSLog(@"%@",elementName);
103     
104     
105     //这里拿到的标签  代表的是结束标签  同时代表数据已经解析完毕
106     //新添加的数组一定在数组最后的位置,所以这里用lastObject可以取到刚去到的那一个
107     Model *model = self.dataArray.lastObject;
108     
109 
110     [model  setValue:self.string forKey:elementName];
111     
112 }
113 
114 //结束解析
115 -(void)parserDidEndDocument:(NSXMLParser *)parser
116 {
117     NSLog(@"结束解析");
118     //快速遍历
119     for (Model * m in  self.dataArray) {
120         NSLog(@"%@ %@ %@ %@ ",m.reciver,m.sender,m.date,m.content);
121     }
122 
123 }
124 
125 //解析发生错误时会走
126 -(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
127 {
128     NSLog(@"解析发生错误时会走");
129 
130 }

 

 
  4.DOM解析(采用GDataXMLNode解析类)
     1>.概念:DOM:Document Object Model(文档对象模型)。解析时需要将XML文件整体读入,并且将XML结构化成树状,使用时再通过树状结构读取相关数据.
     2>.GDataXMLNode是Google提供的开源XML解析类,对libxml2.dylib进⾏行了Objective-C的封装    并且采用DOM方式解析数据
     3>.iOS中包含一个C语言的动态链接库libxml2.dylib,解析速度比 NSXMLParser快
     4>.DOM
       使用的是libxml2.dylib静态库。常用的是谷歌公司开源的GDataXMLNode(MRC)。把一个XML文件转化成一个树形的结构。先找到跟节点,之后再去找跟节点的子节点,在去找子节点的子节点。
 
 1 //使用DOM 解析
 2 - (IBAction)buttonClick:(UIButton *)sender {
 3     
 4     
 5     NSString *pathStr = [[NSBundle  mainBundle] pathForResource:@"date.txt" ofType:nil];
 6     
 7     NSData *data = [NSData dataWithContentsOfFile:pathStr];
 8     
 9     //DOM解析**********************************
10     
11     //初始化一个GData的实例   获取所有文件
12     GDataXMLDocument  *XMLDocument = [[GDataXMLDocument alloc] initWithData:data options:0 error:nil];
13     //获取根节点
14     GDataXMLElement *rootElement = XMLDocument.rootElement;
15     
16     //初始化数组
17     self.dataArray = [NSMutableArray array];
18     //GDataXMLElement  查找结点的类
19     for (GDataXMLElement *son in rootElement.children) {
20         
21         Model *model = [[Model alloc] init];
22         [self.dataArray addObject:model];
23         for (GDataXMLElement *child in son.children) {
24             //stringValue 代表结点里面的数据
25             //name代表结点的名字
26             [model setValue:child.stringValue forKey:child.name];
27         }
28     }
29     //遍历打印
30     for (Model * m in  self.dataArray) {
31         NSLog(@"%@ %@ %@ %@ ",m.reciver,m.sender,m.date,m.content);
32     }
33     
34 }

 

   注意: XML的数据,基本上只存在于天气预报

 
 
三.JSON解析
 
 1.基本介绍
   1>.概念:Javascript Object Notation,轻量级的数据交换格式,采用完全 独立于语言的文本格式,被称为理想的数据交换语言
   2>.基本认识: JSON文档有两种结构:对象、数据
   对象:以“{”开始,以“}”结束,是“名称/值”对⼉儿的集合。名称和值中 间⽤用“:”隔开。多个“名称/值”对之间⽤用“,”隔开。类似OC中的字典。
   数组:以“[”开始,以“]”结束,中间是数据。数据以“,”分隔。 JSON中的数据类型:字符串、数值、BOOL、对象、数组。
   3>.对于JSON数据结构一般采用两种形式进行解析JSONJSONKit.
 
 2..JSON数据解析 (采用NSJSONSerialization对象)
    JSON解析时系统的自带的
    只能把一段NSData转成我们想要的数据结构。接收数据的时候,一定要分析好用什么接收。
 
 
代码详解:
 
 1 //JSON数据解析***************************************
 2 - (IBAction)JsonButtonclick:(UIButton *)sender {
 3     
 4     NSString *pathFile = [[NSBundle mainBundle] pathForResource:@"date2.txt" ofType:nil];
 5     //接收文件数据
 6     NSData * data = [NSData dataWithContentsOfFile:pathFile];
 7     
 8     //使用JSON解析数据
 9     
10     // NSJSONReadingMutableContainers 代表返回一个可变数组或者字典
11     // NSJSONReadingMutableLeaves 代表返回一个字符串
12     // NSJSONReadingAllowFragments 可以用任意类型接收
13     NSArray *array = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
14     
15     NSLog(@"%@",array);
16     
17     self.dataArray = [NSMutableArray array];
18 //    NSLog(@"%@",array);
19     for (NSDictionary *dic in array) {
20         
21         Model *model = [[Model alloc] init];
22         
23         [model setValuesForKeysWithDictionary:dic];
24         //把model添加进数组
25         [self.dataArray addObject:model];
26         
27     }
28     
29     //快速遍历
30     for (Model * m in  self.dataArray) {
31         
32         NSLog(@"%@ %@ %@ %@ ",m.reciver,m.sender,m.date,m.content);
33     }
34 
35 }

 

 
  3.JSONKit 解析

    如果需要解析一个JSON格式的字符串,就需要使用JSONKit了。
 
 
代码详解:
 
 1 //JSONKit 解析**********************************
 2 
 3 - (IBAction)JSONKit:(UIButton *)sender {
 4     
 5     NSString *pathFile = [[NSBundle mainBundle] pathForResource:@"date2.txt" ofType:nil];
 6     //接收文件数据
 7     NSData * data = [NSData dataWithContentsOfFile:pathFile];
 8     
 9     NSArray *arr = [data objectFromJSONData];
10     
11     NSLog(@"%@",arr);
12     
13 
14 
15     self.dataArray = [NSMutableArray array];
16     //    NSLog(@"%@",array);
17     for (NSDictionary *dic in arr) {
18         
19         Model *model = [[Model alloc] init];
20         
21         [model setValuesForKeysWithDictionary:dic];
22         //把model添加进数组
23         [self.dataArray addObject:model];
24         
25     }
26     //快速遍历
27     for (Model * m in  self.dataArray) {
28         
29         NSLog(@"%@ %@ %@ %@ ",m.reciver,m.sender,m.date,m.content);
30     }
31     
32     
33 }

 

 
四.总结: 
    1.(1).数据解析:从某种格式的数据中提取自己所需要的数据。
      (2).主流的数据交换格式有两种:XML和JSON XML解析分为两种:SAX解析和DOM解析 XML解析工 具:NSXMLParser、GDataXMLNode、TochXML和KissXML等
      (3).JSON解析工具:JSONKit、NSJSONSerialization、TouchJSON和SBJSON 等,其NSJSONSerialization是系统提供的解析类,其解析效率是最高的
 
    2.最根本的目的:找到一个相对最小的,数组套字典格式的数据,然后就可以将其取出。

 
注意: 在使用GDATA和JSON解析时需要更改成三处地方  (GDATA和JSON解析文件文件)
 
 
 
 
 
 
 
 
 
 
 
 
 
 五.扩展之单例的创建.(利用GCD线程创建单例对象)
 

     单例模式的意思就是只有一个实例。单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

1.单例模式的要点:

  显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

2.单例模式的优点:

  1>.实例控制:Singleton 会阻止其他对象实例化其自己的 Singleton 对象的副本,从而确保所有对象都访问唯一实例。
  2>.灵活性:因为类控制了实例化过程,所以类可以更加灵活修改实例化过程

   总结:我们看到,该方法的作用就是执行且在整个程序的声明周期中,仅执行一次某一个block对象。简直就是为单例而生的嘛。而且,有些我们需要在程序开头初始化的动作,如果为了保证其,仅执行一次,也可以放到这个dispatch_once来执行。

     然后我们看到它需要一个断言来确定这个代码块是否执行,这个断言的指针要保存起来,还需要多保存一个指针。

    方法简介中就说的很清楚了:对于在应用中创建一个初始化一个全局的数据对象(单例模式),这个函数很有用。

如果同时在多线程中调用它,这个函数将等待同步等待,直至该block调用结束。

 
创建过程:
 
 playHelper.h文件
 
 #import <Foundation/Foundation.h>
 
 @interface playHelper : NSObject
 
 
 +(playHelper *)sharedHelper;
 
 
 @end


playHelper.m文件
 @implementation playHelper
 
 //第一次调用这个方法  单例对象就存在,之后就可以使用(单例会占用静态区的内存)
 
 //单例在静态区,不会二次初始化
 
 +(playHelper *)sharedHelper
 {
     static playHelper *player = nil;
     //dispatch_once_t 代理同一时间内,只有一个线程访问它  防止两个线程访问它
     //单例:在静态去初始化一个对象,把这个类放在静态区   程序结束时释放
     //作用传值(跨界面传值)
     //全局的  第一次调用就存在  以后可以使用
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         if (player == nil) {
             player = [[playHelper alloc] init];
         }
     });
     return player;
 
 }

 

  

 
 
posted @ 2015-09-29 22:22  DengHuiCheng  阅读(217)  评论(0编辑  收藏  举报