在网络开发中, 从服务器获取的数据都为二进制形式的, 最常见的有JSON/XML, 我们需要对这些数据进行解析.
序列化&反序列化
- 反序列化:在从服务器接收到数据之后,将二进制数据转换成 NSArray / NSDictionary
- 序列化:在向服务器发送数据之前,将 NSArray / NSDictionary 转换成二进制的过程
JSON解析
JSON语法规则
- 数据以 key/value 值对表示
- 数据由逗号分隔
- 花括号保存对象
- 方括号保存数组
JSON反序列化
id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
NSLog(@"%@", result);
JSON解析苹果原生类: NSJSONSerialization
1> 专门负责JSON 和 Foundation 对象直接转换的类
2> 可转换成 JSON 的 Foundation 对象需要具备以下条件:
* 顶级节点是 NSArray 或者 NSDictionary
* 所有的对象是 NSString, NSNumber, NSArray, NSDictionary 或者 NSNull
* 所有字典的 key 是 NSString
* NSNumber 不是空或者无穷大
JSON解析第三方框架: JSONKit
使用:
id result = [[JSONDecoder decoder] objectWithData:data];
注意:
官方说JSONKit比苹果原生的JSON解析速度快, 但经过性能测试NSJSONSerialization会更快一些, 因此建议使用NSJSONSerialization
XML解析
- XML介绍
XML 指可扩展标记语言(eXtensible Markup Language)
XML被设计用来传输和存储数据
解析方式有两种:
DOM解析
是在 MAC 使用的解析方式
内存消耗极大,不适用于手机
iPhone无法直接使用 DOM 方式解析 XML
SAX解析
是只读的方式,从上向下的方式解析
是苹果提供的解析方式
速度快
NSXMLParser 通过代理实现解析
- 代码实现
// data为网络请求回来的数据
// 1. 使用网络返回的二进制数据实例化 NSXMLParser 对象
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
// 2. 设置代理,通过代理方法实现 SAX 解析
parser.delegate = self;
// 3. 开始解析
[parser parse];
- // 单节点SAX解析
// MARK: - NSXMLParserDelegate
// 开始解析元素
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSLog(@"attributeDict:%@",attributeDict);
if ([elementName isEqualToString:@"vedio"]) {
// 字典转模型
EJVideo *video = [EJVideo videoWithDict:attributeDict];
[self.videos addObject:video];
}
}
- // 多节点SAX解析
// 开始解析元素
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
// 有多少个 vedio 元素就创建多少个 数据模型!
if ([elementName isEqualToString:@"vedio"]) {
self.video = [[EJVideo alloc] init];
}
}
// 发现元素内容
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// 元素内容是 value 值
// setString 替换字符串,每次新发现元素内容之后,将新的元素内容替换掉原来的元素内容!
[self.currentElementString setString:string];
}
// 元素解析结束
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
// 模型中的每一个属性节点, 设置到模型中
if ([elementName isEqualToString:@"ID"]) {
[self.video setValue:self.currentElementString forKey:elementName];
}
if ([elementName isEqualToString:@"image"]) {
[self.video setValue:self.currentElementString forKey:elementName];
}
if ([elementName isEqualToString:@"length"]) {
[self.video setValue:self.currentElementString forKey:elementName];
}
if ([elementName isEqualToString:@"name"]) {
[self.video setValue:self.currentElementString forKey:elementName];
}
if ([elementName isEqualToString:@"url"]) {
[self.video setValue:self.currentElementString forKey:elementName];
}
// 当 每一个vedio元素解析结束的时候,都将这个数据模型添加到数据源中.
if ([elementName isEqualToString:@"vedio"]) {
[self.videos addObject:self.video];
}
}