数据解析

在网络开发中,从服务器获取的二进制数据包括:

> html

>图片

>视频

>音频

> zip等

除了以上文件格式之外,最常见的数据莫过于JSON,偶尔也会有XML。

无论JSON还是XML都是一种特殊格式的字符串,按照特定的规则描述数据结构。

一、准备工作--->安装Apache服务器

>参考备课笔记/笔记/02-Apache服务器安装笔记.m

二、JSON

1、JSON格式介绍

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

> JSON是网络上用来传输数据使用最广泛的数据格式,没有之一。

> JSON出生草根,是Javascript的子集,是Javascript的SON,专门用来描述数据结构。

> Javascrpit是做网页开发使用的一种"脚本"语言

> Javascrpit & Java没有任何关系!就好像雷锋和雷峰塔之间的关系。

#参考网站:http//www.w3cschool.cc。w3c是国际互联网组织的缩写。

2、JSON的语法规则

>数据以key/value键值对表示

>数据由逗号分割

>花括号保存对象,对应OC的NSDictionary。

>方括号保存数组,对应OC的NSArray。

3> JSON值

*数字(整数或浮点数)

*字符串(在双引号中)

*逻辑值(true或false)

*数组(在方括号中)

* null

4、JSON解析--->解析天气预报

>序列化:在向服务器发送数据之前,将NSArray/NSDcitionary转成二进制的过程。

>反序列化:在从服务器接收到数据之后,将二进制数据转换成NSArray/NSDcitionary的过程。

/**

*解析天气预报

*/

- (void)loadData{

//创建url

NSURL *url = [NSURL URLWithString:@"http://www.weather.com.cn/adat/sk/101010100.html"];

//创建请求对象

NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0timeoutInterval:10.0];

//发送异步请求

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

NSLog(@"data = %@",data);

/*

>序列化:在向服务器发送数据之前,将NSArray/NSDcitionary转成二进制的过程。

>反序列化:在从服务器接收到数据之后,将二进制数据转换成NSArray/NSDcitionary的过程。

*/

NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);

/*

NSJSONReadingMutableContainers = (1UL << 0),容器可变

NSJSONReadingMutableLeaves = (1UL << 1),叶子可变

NSJSONReadingAllowFragments(碎片) = (1UL << 2)顶级节点可以既不是数组也不是字典

*/

NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0error:NULL];

NSLog(@"%@市温度%@风向%@风力%@ ",dict[@"weatherinfo"][@"city"],dict[@"weatherinfo"][@"temp"],dict[@"weatherinfo"][@"WD"],dict[@"weatherinfo"][@"WS"]);

}];

}

5、JSON解析第三方框架

>常见的JSON解析第三方框架

* JSONKit(最快)

* SBJson

* TouchJSON

#以上三个框架的性能依次降低。

>介绍JSONKit第三方框架的目的

* JSON的解析并不是表面上这么简单

*官方说JSONKit比苹果原生的JSON解析速度要快。

* JSONKit在很多老的项目中仍然在使用

#知道JSONKit说明我们是资深的iOS程序员。

* JSONKit已经在2012年停止更新,适用于iOS5.0之前的版本开发使用。(苹果原生的NSJSONSerialization是iOS5.0之后出现)

*了解ARC & MRC混编的方法

> JSONKit解析和性能测试

使用步骤:

*下载框架:http://github.com/johnezang/JSONKit

*导入框架文件:JSONKit.h & JSONKit.m

*设置MRC标记

>选择"项目"-"Build Phases"-"Compile Sources"

>找到JSONKit.m并且在Compiler Flags中添加-fno-objc-arc。

# -fno-objc-arc告诉编译器,编译JSONKit.m时不使用ARC。

*修改错误

>利用自动修复功能,修改两处isa的错误。

*反序列化

>idresult =  [[JSONDecoder decoder] objectWithData:data];

使用代码和测试如下:

intlargeNumber =100*1000;

- (void)loadData{

//创建url

NSURL *url = [NSURL URLWithString:@"http://localhost/demo.json"];

//创建请求对象

NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0timeoutInterval:10.0];

//发送异步请求

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

/*

官方说JSONKit比苹果原生的JSON解析速度要快。我们可以通过测试验证下

JSONKit:4.907761秒

官方:0.299994秒

通过测试得出:苹果原生的JSON解析速度远远比JSONKit快。

如果工作中遇到使用第三方框架解析JSON的旧项目,建议替换为苹果原生的。

替换的原则:看项目是否要支持iOS5.0之前的版本。如果不需要果断替换。

替换步骤:

1>备份(给自己一个后悔的机会)

2>删除JSONKit.h & .m文件

3>哪里出错改哪里

*/

CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();

for(intindex =0; index < largeNumber; index ++) {

//            NSMutableDictionary *result =  [[JSONDecoder decoder] objectWithData:data];

NSMutableDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0error:NULL];

}

NSLog(@"-----endTime = %f",CFAbsoluteTimeGetCurrent() - start);

//JKDictionary其实就是NSMutableDictionary的子类

//         NSLog(@"------%@,%@",result,result[@"message"]);

}];

}

6、PList解析

> PList主要在苹果开发中常用,很多后台并不会返回Plist的格式数据。有关PList的反序列化知道即可。

>代码如下:

/**

*解析plist数据

*/

- (void)loadData{

//创建url

NSURL *url = [NSURL URLWithString:@"http://localhost/videos.plist"];

//创建请求对象

NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0timeoutInterval:10.0];

//发送异步请求

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

/**

参数:

- data:要反序列化的二进制数据

- options:选项,位移枚举类型

NSPropertyListImmutable = 0不可变,

NSPropertyListMutableContainers = 1容器可变,

NSPropertyListMutableContainersAndLeaves = 2容器和叶子可变

- format:如果不希望知道格式,传人NULL即可

- error:错误信息

*/

idresult = [NSPropertyListSerialization propertyListWithData:data options:0format:NULLerror:nil];

NSLog(@"%@   %@",result,[result class]);

}];

}

三、XML解析

1、XML介绍

> XML的英文全称(eXtensible Markup Language),中文名称可扩展标记语言。

> XML的特点:语法规则很简单,且很有逻辑。

#出身名门,w3c制定,微软和IBM曾经共同大力推荐过的数据格式。

>专门设计用来传输和存储数据

>与HTML的区别:HTML的标记不是所有的都需要成对出现,

XML要求所有的标记必须成对出现。

HTML标记不区分大小写,它则大小敏感,即区分大小写。

2、XML解析的方式

> DOM解析

*是在MAC使用的解析方式。

*内存消耗极大,不适用于手机。因此苹果没有提供手机上DOM解析。

* iPhone无法直接使用DOM方式解析XML。

> SAX解析

*是只读的方式,从上向下的方式解析

*是苹果提供的解析方式

*使用NSXMLParser通过代理实现解析。

3、SAX解析步骤

1>开始文档--准备工作

2>开始"节点"

3>发现节点内部的内容,每一个节点,可能需要多次才能找完

4>结束"节点"

5>结束文档--解析结束

#以上步骤,2,3,4会不断循环,一直到所有解析完成。

4、代码演示XML的解析。

/**

*加载xml数据

*/

- (void)loadData{

//创建url

NSURL *url = [NSURL URLWithString:@"http://localhost/videos.xml"];

//创建请求对象

NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0timeoutInterval:10.0];

//发送异步请求(由于解析xml是一个耗时的过程,所以新开启队列)

[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

// 1.创建xml解析器

NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

// 2.设置代理来解析

parser.delegate =self;

// 3.解析器开始解析--一旦开始解析,后续的解析工作全部交给代理完成

[parser parse];

}];

}

>通过NSLog打印,确认XML解析思路

#pragma mark  - NSXMLParserDelegate代理方法

/**

*开始解析

*/

- (void)parserDidStartDocument:(NSXMLParser *)parser {

NSLog(@"1、开始解析");

}

/**

*解析到一个开始节点调用

*/

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {

NSLog(@"2、开始节点%@ %@",elementName,attributeDict);

}

/**

*解析到节点文字调用一个节点的内容可以会调用多次该方法

*/

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {

NSLog(@"3、======> %@",string);

}

/**

*解析到结束节点调用elementName没有反斜线/

*/

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

NSLog(@"4、结束节点------%@",elementName);

}

/**

*解析结束调用

*/

- (void)parserDidEndDocument:(NSXMLParser *)parser{

NSLog(@"5、结束文档");

}

5、画XML解析思维导图

6、XML解析代码实现

#pragma mark  - NSXMLParserDelegate代理方法

/**

*开始解析

*/

- (void)parserDidStartDocument:(NSXMLParser *)parser {

//清空数组

[self.videos removeAllObjects];

}

/**

*解析到一个开始节点调用

*/

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {

if([elementName isEqualToString:@"video"]) {

//创建video模型

self.currentVideo = [[Video alloc] init];

//设置id

self.currentVideo.videoId =@([attributeDict[@"videoId"] integerValue]);

}

//清空当前正在拼接的字符内容

[self.elementString setString:@""];

//错误写法

//self.elementString = @"";

}

/**

*解析到节点文字调用一个节点的内容可以会调用多次该方法

*/

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {

[self.elementString appendString:string];

}

/**

*解析到结束节点调用elementName没有反斜线/

*/

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

//如果elementName是video,则添加到数组中

/*最笨方法

if ([elementName isEqualToString:@"video"]){

[self.videos addObject:self.currentVideo];

} else if ([elementName isEqualToString:@"name"]){

self.currentVideo.name= self.elementString;

} else if ([elementName isEqualToString:@"length"]){

self.currentVideo.length = @(self.elementString.integerValue);

} else if ([elementName isEqualToString:@"desc"]){

self.currentVideo.desc = self.elementString;

} else if ([elementName isEqualToString:@"imageURL"]) {

self.currentVideo.imageURL = self.elementString;

} else if ([elementName isEqualToString:@"videoURL"]){

self.currentVideo.videoURL = self.elementString;

} else if ([elementName isEqualToString:@"teacher"]){

self.currentVideo.teacher = self.elementString;

}

*/

//如果是name,length,desc....则设置属性

//简便方法

if([elementName isEqualToString:@"video"]){

[self.videos addObject:self.currentVideo];

}elseif(![elementName isEqualToString:@"videos"]){

//使用KVC设置属性, KVC是一种以字符串形式间接设置数据的方式

[self.currentVideo setValue:self.elementString forKey:elementName];

}

}

/**

*解析结束调用

*/

- (void)parserDidEndDocument:(NSXMLParser *)parser{

NSLog(@"%@",self.videos);

}

四、tableView展示数据

1、展示视频数据--Storyboard自定义cell

2、设置时间格式

> HMVideo模型中提供属性

//视频时长

@property(nonatomic,strong,readonly) NSString *time;

#计算时间方式有两种

#方式一:重写time属性getter方法

- (NSString *)time {

intlen =self.length.intValue;

return[NSString stringWithFormat:@"%02d:%02d:%02d", len /3600, (len %3600) /60, (len %60)];

}

#方式二:

- (void)setLength:(NSNumber *)length {

_length = length;

intlen =self.length.intValue;

_time = [NSString stringWithFormat:@"%02d:%02d:%02d", len /3600, (len %3600) /60, (len %60)];

}

3、SDWebImage下载头像

UIImage *placeholder = [UIImage imageNamed:@"user_default"];

// SDWebImageLowPriority:会在表格滚动的时候,暂时图像下载,性能会好很多

// SDWebImageRetryFailed:图片下载失败后重试

[self.iconView sd_setImageWithURL:video.fullImageUrl placeholderImage:placeholder options:SDWebImageRetryFailed | SDWebImageLowPriority];

4、集成下列刷新控件-->通过代码和storyboard

/**

*集成下拉刷新控件(通过代码)

*/

- (void)setRefreshControl{

//集成下拉控件(不需要设置frame)

self.refreshControl = [[UIRefreshControl alloc] init];

//监听下拉事件

[self.refreshControl addTarget:selfaction:@selector(loadData) forControlEvents:UIControlEventValueChanged];

//设置提示文字,颜色

NSMutableAttributedString *attributedTitle = [[NSMutableAttributedString alloc] initWithString:@"努力加载中……"attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15],NSForegroundColorAttributeName:[UIColor redColor]}];

self.refreshControl.attributedTitle = attributedTitle;

//设置菊花颜色

self.refreshControl.tintColor = [UIColor grayColor];

}

# UIRefreshControl使用说明

1>目前只对UITableviewController有用

2>只能下拉刷新,不能上拉刷新

3> init或者viewdidload中创建UIRefreshControl,设置文字,颜色等信息

4>系统自动管理UIRefreshControl,自动添加到tableview视图中;

5>给UIRefreshControl添加方法,当值改变的时候调用,方法用于数据请求

6>该方法中请求数据确认完成之后,调用endRefreshing方法,关闭刷新

五、XML解析重构

1>新建一个模型类HMSAXVideo,专门做解析工作。

2>提供类方法:+(void)saxParser:(NSData *)data finished:(void(^)(NSArray *))finished。

//如果回调的block在当前方法不执行,需要用一个属性记录

+(void)saxParser:(NSData *)data finished:(void(^)(NSArray *))finished{

//使用断言确保外界传人的回调不为空,如果为空,则崩溃提示

NSAssert(finished !=nil,@"必须传人回调");

// 0.创建解析模型

HMSAXVideo *sax = [[HMSAXVideo alloc] init];

//记录回调block

sax.finishedBlock = finished;

// 1.创建xml解析器

NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

// 2.设置代理来解析

parser.delegate = sax;

// 3.解析器开始解析

// parse:是同步方法,会等所用代理方法执行完毕后,才会执行后面的代码

[parser parse];

#warning不能在parse方法调用后记录回调

//记录回调block

// sax.finishedBlock = finished;

}

六、Copy,NSNumber,id

1、为什么模型HMVideo中的属性都使用copy?改为strong运行看看效果。

> strong:在设置数值的时候,仅仅是引用计算+1

> copy:在设置数值的时候,如果有方法是可变的,会copy一个不可变的副本。copy动作是在setter方法中执行的。

>画图解析使用strong导致的效果。

>如果属性使用strong:

#下面的代码

[self.currentVideo setValue:self.elementString forKey:elementName];

#修改为

[self.currentVideo setValue:self.elementString.copy forKey:elementName];

>重新了属性的setter方法,就是接管了原有系统提供的setter方法。

#如果重新了copy属性的setter方法,一定要copy,否则外面的copy属性就是strong属性。

比如重写了模型的name属性的setter方法:

- (void)setName:(NSString *)name {

_name = [name copy];

//    _name = name;属性就相当于strong了

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容