简介
网络数据传输通用的格式有JSON、Plist、Xml等。首先要清楚网络数据传输的逻辑:序列化和反序列化。序列化是指将数据转换成二进制数据流在网络中传输;反序列化是指将二进制数据流转化成我们能使用的数据,在OC中转换成数据对象,通过JSON、Plist、XML等数据解析完成反序列化。
- JSON:轻量级的数据交换格式,目前移动开发绝大多数在使用这种格式。JSON出自于民间,语法是JavaScript对象标识的语法子集,本质上就是一种特殊的字符串,OC中的NSDictionary的快速包装的方法就是借鉴了JSON。JSON解析的三方框架有JSONKit、SBJson、TouchJson等一些古老的解析三方,这里只介绍苹果的NSJSONSerialization。
JSON的格式:
[{
"id":1,
"username":"zhangsan",
"age":18
},
{
"id":2,
"username":"xiaohua",
"age":null
}]
[ ]保存数组,{ }保存对象,对应OC中的NSArray和NSDictionary结构很相近。
-
Plist:在实际的开发中,不管是Java后台、PHP后台,很少用到。Plist在苹果Mac、iOS中使用的比较多。
Plist格式:
- XML:是曾经最流行的格式,出身名门,由W3C主推,微软和IBM推荐使用。xml是可扩展"标记"语言,格式
<标记>标记>
<标记>内容标记>
<标记 属性1=“值”,属性2=“值”>标记内容</标记>
解析方式:DOM、SAX
DOM MAC提供的解析方式,iOS无法使用,主要原因跟是内存开销太大;SAX是iOS提供的解析方式,内存开销小、速度快,但是只读,无法修改xml文件。这里着重介绍SAX解析。
数据解析
通过网络请求获取数据
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1/XXX"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
}]
获取到不同格式的数据data,下面根据不同的数据格式,分别介绍其解析方式。
- JSON:
NSJSONSerialization是iOS 5.0 推出的JSON解析,主要是将网络请求的二进制数据转换成NSArray或NSDictionary。
在NSJSONSerialization头文件中对JSON的介绍如下:
An object that may be converted to JSON must have the following properties:
- Top level object is an NSArray or NSDictionary
- All objects are NSString, NSNumber, NSArray, NSDictionary, or NSNull
- All dictionary keys are NSStrings
- NSNumbers are not NaN or infinity
一个JSON对象应该具备以下属性
- 顶级节点是一个 NSArray或者 NSDictionary
- 所有的对象必须是 NSString, NSNumber, NSArray, NSDictionary, or NSNull
- 所有字典的Key必须是NSString
- NSNumber 不能使无理数或者空
解析
/**
Options参数:
NSJSONReadingMutableContainers = (1UL << 0), 容器节点是可变的
NSJSONReadingMutableLeaves = (1UL << 1), 子节点是可变的
NSJSONReadingAllowFragments = (1UL << 2) 允许顶级节点不是 NSArray或NSDictionary
*/
id result = [NSJSONSerialization JSONObjectWithData:data options:1 error:NULL];
NSLog(@"%@ %@",result,[result class]);
for (NSDictionary *dic in result) {
NSLog(@"==>%@",dic);
}
result 可能是数组、字典,一般根据后台给的文档可以判断区分,最外层是[ ] 则result是一个数组,如果是{ } 则result是一个字典。
- Plist
NSPropertyListSerialization解析
//解析数据
//NSJSONSerialization JSON 序列化
//Plist 序列化 用 NSPropertyListSerialization
/**
NSPropertyListImmutable plist属性列表不可变
NSPropertyListMutableContainers 容器可变
NSPropertyListMutableContainersAndLeaves 容器和子节点都可变
*/
id result = [NSPropertyListSerialization propertyListWithData:data options:0 format:NULL error:NULL];
NSLog(@"%@ %@",result,[result class]);
- XML
要解析的数据
SAX解析过程包括5个步骤,其实通过NSXMLParser的代理可以充分体现,具体步骤分为
(1)打开文档
(2)开始节点
// XML解析需要的素材
// 1.可变数组
@property (strong, nonatomic) NSMutableArray *videos;
// 2.可变字符串
@property (strong, nonatomic) NSMutableString *elementStr;
// 3.当前解析的节点 -- 模型
@property (strong, nonatomic) Video *currentVideo;
- (NSMutableString *)elementStr{
if (!_elementStr) {
_elementStr = [NSMutableString string];
}
return _elementStr;
}
- (NSMutableArray *)videos{
if (!_videos) {
_videos = [NSMutableArray array];
}
return _videos;
}
//XML 解析 -- 耗时操作
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
//设置代理
parser.delegate = self;
//解析器解析
[parser parse];
重点是在代理方法中整理数据
//1.打开文档
- (void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(@"1.开始文档");
//清空数组
[self.videos removeAllObjects];
}
//2.开始节点 (Element - 元素) attributeDict 包含在开始节点内的扩展属性
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
NSLog(@"2.开始节点: \n节点名称: %@ \n节点属性: %@",elementName,attributeDict);
//先判断element是不是video,如果是就
if ([elementName isEqualToString:@"video"]) {
self.currentVideo = [[Video alloc]init];
self.currentVideo.videoId = [NSString stringWithFormat:@"%ld",[attributeDict[@"videoId"] integerValue]];
}
}
//3.发现节点内容
- (void)parser:(NSXMLParser *)parser foundCharacters:(nonnull NSString *)string{
//拼接字符串
NSLog(@"3.发现节点内容 =====> %@",string);
[self.elementStr appendString:string];
}
//4.结束节点
/**
KVC key value 键值编码
cocoa 大招!!! kvc
*/
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
NSLog(@"4.结束节点 %@",elementName);
if ([elementName isEqualToString:@"video"]) {
[self.videos addObject:self.currentVideo];
}else if (![elementName isEqualToString:@"videos"]){
[self.currentVideo setValue:self.elementStr forKey:elementName];
}
[self.elementStr setString:@""];
}
//5.结束文档
- (void)parserDidEndDocument:(NSXMLParser *)parser{
NSLog(@"5.结束文档 %@ %@",parser,self.videos);
}
//6.出现错误
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSLog(@"6.出现错误 %@",parseError);
}