第十五讲.数据解析(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的类完成解析的目的,是逐行解析的,当解析到跟节点的结束标识的时候,结束解析。缺点:解析的慢,不是特别准确。使用的代理方法去解析。
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快
2>.GDataXMLNode是Google提供的开源XML解析类,对libxml2.dylib进⾏行了Objective-C的封装 并且采用DOM方式解析数据
3>.iOS中包含一个C语言的动态链接库libxml2.dylib,解析速度比 NSXMLParser快
4>.DOM
使用的是libxml2.dylib静态库。常用的是谷歌公司开源的GDataXMLNode(MRC)。把一个XML文件转化成一个树形的结构。先找到跟节点,之后再去找跟节点的子节点,在去找子节点的子节点。
使用的是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、对象、数组。
对象:以“{”开始,以“}”结束,是“名称/值”对⼉儿的集合。名称和值中 间⽤用“:”隔开。多个“名称/值”对之间⽤用“,”隔开。类似OC中的字典。
数组:以“[”开始,以“]”结束,中间是数据。数据以“,”分隔。 JSON中的数据类型:字符串、数值、BOOL、对象、数组。
3>.对于JSON数据结构一般采用两种形式进行解析JSON和JSONKit.
2..JSON数据解析 (采用NSJSONSerialization对象)
JSON解析时系统的自带的
只能把一段NSData转成我们想要的数据结构。接收数据的时候,一定要分析好用什么接收。
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).主流的数据交换格式有两种: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;
}