前言
- 本文是解析 XML(用XML語言寫的數(shù)據(jù)) 和 JSON格式的數(shù)據(jù)
-
在此聲明:XML是一種語言,JSON是一種數(shù)據(jù)格式
30-01.png
一.解析JSON格式的數(shù)據(jù)(即:反序列化)
利用NSJSONSerialization對JSON格式的數(shù)據(jù)進行解析
當數(shù)據(jù)結(jié)構(gòu)為 {key:value,key:value,...}的鍵值對的結(jié)構(gòu)時,可以解析成NSDictionary.
當數(shù)據(jù)結(jié)構(gòu)為 ["a","b","c",...]結(jié)構(gòu)時筷凤,可以解析成NSArray.
NSJSONSerialization類中的兩個方法
- JSON數(shù)據(jù)轉(zhuǎn)成OC對象(反序列化)--->解析JSON格式的數(shù)據(jù)就用這個方法
- 反序列化目的(通俗理解):轉(zhuǎn)換成OC格式,對于學習OC語法的人來說,能容易看懂
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
- OC對象轉(zhuǎn)成JSON數(shù)據(jù)(序列化)
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
序列化與反序列化:
- 序列化:在傳輸之前,將對象轉(zhuǎn)換成有序的字符串或者二進制數(shù)據(jù)流
- 反序列化:將已經(jīng)接收到的字符串或者二進制數(shù)據(jù)流 轉(zhuǎn)換成對象或者數(shù)組,以便程序訪問
注意:
- Json本質(zhì)上是具有特殊格式的字符串
- 解析Json的過程就是反序列化的過程
- 在線代碼格式化:http://tool.oschina.net/codeformat/json
- 區(qū)分字典和數(shù)組
- 字典{:镇草,:馋记,}就是key:vaule的形式酿炸,既有冒號又有逗號
- 數(shù)組[,,,,]中都是逗號隔開
JSON數(shù)據(jù)轉(zhuǎn)成OC對象的詳情代碼1:
- 注意:創(chuàng)建task使用的是dataTaskWithRequest方法
30-04.png
JSON數(shù)據(jù)轉(zhuǎn)成OC對象的詳情代碼2:
- 注意:創(chuàng)建task使用的是dataTaskWithURL方法
30-05.png
OC對象轉(zhuǎn)成JSON數(shù)據(jù)的詳情代碼:
30-03.png
JSON解析綜合練習(用NSJSONSerialization創(chuàng)建JSON解析器)
- 注意區(qū)分里面的面向字典開發(fā)和面向模型
#import "ViewController.h"
#import "UIImageView+WebCache.h"
#import "ZBTableViewCell.h"
#import "ZBVideo.h"
#import <MediaPlayer/MediaPlayer.h>
#import "MJExtension.h"
#define BaseURL @"http://120.25.226.186:32812"
@interface ViewController ()
/** 數(shù)據(jù)源*/
@property (nonatomic ,strong) NSArray *videos;
@end
@implementation ViewController
#pragma mark --------------------
#pragma mark Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
//有了這句代碼状原,模型中的ID本質(zhì)對應著的是數(shù)據(jù)庫中的id
//0.告訴框架新值和舊值的對應關(guān)系
[ZBVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
return @{
@"ID":@"id",
};
}];
//1.發(fā)送請求
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=JSON"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//2.解析數(shù)據(jù) (NSJSONSerialization是解析數(shù)據(jù)的標志)
NSDictionary *dictM = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSLog(@"%@",dictM);
//復雜json
//1)寫plist文件到桌面
[dictM writeToFile:@"/Users/zhangbin/Desktop/video.plist" atomically:YES];
//2)json在線格式化 http://tool.oschina.net/codeformat/json
//3.設(shè)置tableView的數(shù)據(jù)源(把服務器返回給我們的dictM進行轉(zhuǎn)換,作為tableView的數(shù)據(jù)源,顯示在模擬器上)
/*
**************************************面向字典開發(fā)**************************************
//a.面向字典開發(fā)
//self.videos = dictM[@"videos"];
**************************************面向模型開發(fā)**************************************
//b.面向模型開發(fā)
NSArray *arrayM = dictM[@"videos"];
//字典數(shù)組---->模型數(shù)據(jù)
NSMutableArray *arr = [NSMutableArray array];
for (NSDictionary *dict in arrayM) {
[arr addObject:[ZBVideo videWithDict:dict]];
}
self.videos = arr;
*/
//************************************面向模型開發(fā)**************************************
//c.利用MJ的框架,進行面向模型開發(fā)(只需要在模型類中聲明對應的屬性菩收,不需要聲明和實現(xiàn)接口方法,并且之前在外界字典轉(zhuǎn)模型需要很多行代碼拨齐,這里只需一行代碼就搞定)
//dictM[@"videos"]
self.videos = [ZBVideo mj_objectArrayWithKeyValuesArray:dictM[@"videos"]];
//4.刷新tableView
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];//當前類必須繼承UITableViewController驰贷,并且在故事板中設(shè)置關(guān)聯(lián)的類就是當前的控制器盛嘿。否則這行代碼打不出來,會提示錯誤
});
}] resume];
}
#pragma mark --------------------
#pragma mark UITableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.videos.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"video";
//1.創(chuàng)建cell
ZBTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
/*
**************************************面向字典開發(fā)**************************************
面向字典開發(fā),設(shè)置數(shù)據(jù)的代碼(取出字典中的key中才能拿到數(shù)據(jù)括袒,例如dictM[@"length"])
//NSDictionary *dictM = self.videos[indexPath.row];
//2.2 設(shè)置標題
cell.textLabel.text = dictM[@"name"];
//2.3 設(shè)置子標題
cell.detailTextLabel.text = [NSString stringWithFormat:@"播放時間:%@ 秒",dictM[@"length"]];
//2.4 設(shè)置圖標
NSURL *url = [NSURL URLWithString:[BaseURL stringByAppendingPathComponent:dictM[@"image"]]];
[cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20200808_28"]];
*/
//**************************************面向模型開發(fā)**************************************
//面向模型開發(fā),設(shè)置數(shù)據(jù)的代碼(直接從模型中訪問屬性即可拿到數(shù)據(jù)次兆,例如ideoM.length)
//2.1 獲得該cell對應的數(shù)據(jù)
ZBVideo *videoM = self.videos[indexPath.row];
//2.2 設(shè)置標題
cell.textLabel.text = videoM.name;
//2.3 設(shè)置子標題
cell.detailTextLabel.text = [NSString stringWithFormat:@"播放時間:%@ 秒",videoM.length];
//2.4 設(shè)置圖標 image是NSString類型的
NSURL *url = [NSURL URLWithString:[BaseURL stringByAppendingPathComponent:videoM.image]];
//占位圖片,當網(wǎng)上的圖片沒下載當指定的cell的時候锹锰,用占位圖片暫時頂替
[cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20200808_28"]];
NSLog(@"%@",videoM.ID);
//3.返回cell
return cell;
}
#pragma mark --------------------
#pragma mark UITableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
/* **************************************面向字典開發(fā)**************************************
//1.拿到該cell對應的數(shù)據(jù)
NSDictionary *dictM = self.videos[indexPath.row];
//播放該cell對應的視頻
NSString *urlStr = [BaseURL stringByAppendingPathComponent:dictM[@"url"]];
*/
//**************************************面向模型開發(fā)**************************************
//1.拿到該cell對應的數(shù)據(jù)
ZBVideo *videoM = self.videos[indexPath.row];
//播放該cell對應的視頻
NSString *urlStr = [BaseURL stringByAppendingPathComponent:videoM.url];
//2.創(chuàng)建視頻播放控制器
MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString:urlStr]];
//3.彈出控制器
[self presentViewController:vc animated:YES completion:nil];
}
@end
上述代碼截圖
30-06.png
二.解析XML
解析XML的兩種做法
- NSXMLParser(適合大文件)
- GDataXMLDocument(不適合大文件)
解析XML的做法一(用NSXMLParser創(chuàng)建XML解析器)
- 注意:和JSON解析綜合練習的區(qū)別:
- 解析數(shù)據(jù)的代碼不一樣
- 讓控制器成為NSXMLParser的代理,代理名稱為NSXMLParserDelegate
- 字典轉(zhuǎn)模型在代理方法中執(zhí)行
#import "ViewController.h"
#import "UIImageView+WebCache.h"
#import "ZBTableViewCell.h"
#import "ZBVideo.h"
#import <MediaPlayer/MediaPlayer.h>
#import "MJExtension.h"
#define BaseURL @"http://120.25.226.186:32812"
@interface ViewController ()<NSXMLParserDelegate>
/** 數(shù)據(jù)源*/
@property (nonatomic ,strong) NSMutableArray *videos;
@end
@implementation ViewController
#pragma mark --------------------
#pragma mark lazy loading
-(NSMutableArray *)videos
{
if (_videos == nil) {
_videos = [NSMutableArray array];
}
return _videos;
}
#pragma mark --------------------
#pragma mark Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
//0.告訴框架新值和舊值的對應關(guān)系
[ZBVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
return @{
@"ID":@"id",
};
}];
//1.發(fā)送請求
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//2.解析數(shù)據(jù)
//2.1 創(chuàng)建XML解析器
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
//2.2 設(shè)置代理
parser.delegate = self;
//2.3 開始解析,該方法本身是阻塞的
[parser parse];
//4.刷新tableView
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}] resume];
}
#pragma mark --------------------
#pragma mark UITableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.videos.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"video";
//1.創(chuàng)建cell
ZBTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
//2.設(shè)置數(shù)據(jù)
//2.1 獲得該cell對應的數(shù)據(jù)
ZBVideo *videoM = self.videos[indexPath.row];
//2.2 設(shè)置標題
cell.textLabel.text = videoM.name;
//2.3 設(shè)置子標題
cell.detailTextLabel.text = [NSString stringWithFormat:@"播放時間:%@ 秒",videoM.length];
//2.4 設(shè)置圖標
NSURL *url = [NSURL URLWithString:[BaseURL stringByAppendingPathComponent:videoM.image]];
[cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20200808_28"]];
NSLog(@"%@",videoM.ID);
//3.返回cell
return cell;
}
#pragma mark --------------------
#pragma mark UITableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//1.拿到該cell對應的數(shù)據(jù)
ZBVideo *videoM = self.videos[indexPath.row];
//播放該cell對應的視頻
NSString *urlStr = [BaseURL stringByAppendingPathComponent:videoM.url];
//2.創(chuàng)建視頻播放控制器
MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString:urlStr]];
//3.彈出控制器
[self presentViewController:vc animated:YES completion:nil];
}
#pragma mark --------------------
#pragma mark NSXMLParserDelegate
//1.開始解析XML文檔
-(void)parserDidStartDocument:(NSXMLParser *)parser
{
NSLog(@"%s",__func__);
}
//2.開始解析某個元素 attributeDict:存放著元素的屬性
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict
{
NSLog(@"%s--開始解析元素%@---\n%@",__func__,elementName,attributeDict);
if ([elementName isEqualToString:@"videos"]) {
//過濾根元素
return;
}
ZBVideo *videoM = [[ZBVideo alloc]init];
[videoM mj_setKeyValues:attributeDict];
[self.videos addObject:videoM];//先調(diào)用videos的懶加載方法芥炭。再將模型裝進大的數(shù)組中
}
//3.某個元素解析完畢
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
NSLog(@"%s--結(jié)束%@元素的解析",__func__,elementName);
}
//4.整個XML文檔都已經(jīng)解析完畢
-(void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(@"%s",__func__);
}
@end
利用NSXMLParser解析XML和利用NSJSONSerialization解析JSON數(shù)據(jù)的區(qū)別
30-07.png
30-08.png
30-09.png
解析XML的做法二(用GDataXMLDocument創(chuàng)建XML解析器)
- 注意:和NSXMLParser的區(qū)別:
- 解析數(shù)據(jù)的代碼不一樣
- 不需要設(shè)置代理
#import "ViewController.h"
#import "UIImageView+WebCache.h"
#import "ZBTableViewCell.h"
#import "ZBVideo.h"
#import <MediaPlayer/MediaPlayer.h>
#import "MJExtension.h"
#import "GDataXMLNode.h"
#define BaseURL @"http://120.25.226.186:32812"
@interface ViewController ()<NSXMLParserDelegate>
/** 數(shù)據(jù)源*/
@property (nonatomic ,strong) NSMutableArray *videos;
@end
@implementation ViewController
#pragma mark --------------------
#pragma mark lazy loading
-(NSMutableArray *)videos
{
if (_videos == nil) {
_videos = [NSMutableArray array];
}
return _videos;
}
#pragma mark --------------------
#pragma mark Life Cycle
- (void)viewDidLoad
{
[super viewDidLoad];
//有了這句代碼,模型中的ID本質(zhì)對應著的是數(shù)據(jù)庫中的id
//0.告訴框架新值和舊值的對應關(guān)系
[ZBVideo mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
return @{
@"ID":@"id",
};
}];
//1.發(fā)送請求
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//2.解析數(shù)據(jù)
//2.1 加載整個XML文檔
GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:data options:kNilOptions error:nil];
//2.2 拿到根元素,得到根元素內(nèi)部所有名稱為video的屬性
NSArray *eles = [doc.rootElement elementsForName:@"video"];
//2.3 遍歷所有的子元素,得到元素內(nèi)部的屬性數(shù)據(jù)
for (GDataXMLElement *ele in eles) {
ZBVideo *videoM = [[ZBVideo alloc]init];
videoM.name = [ele attributeForName:@"name"].stringValue;
videoM.image = [ele attributeForName:@"image"].stringValue;
videoM.ID = [ele attributeForName:@"id"].stringValue;
videoM.length = [ele attributeForName:@"length"].stringValue;
videoM.url = [ele attributeForName:@"url"].stringValue;
[self.videos addObject:videoM];
}
//4.刷新tableView
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}] resume];
}
#pragma mark --------------------
#pragma mark UITableViewDataSource
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.videos.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID = @"video";
//1.創(chuàng)建cell
ZBTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
//2.設(shè)置數(shù)據(jù)
//2.1 獲得該cell對應的數(shù)據(jù)
ZBVideo *videoM = self.videos[indexPath.row];
//2.2 設(shè)置標題
cell.textLabel.text = videoM.name;
//2.3 設(shè)置子標題
cell.detailTextLabel.text = [NSString stringWithFormat:@"播放時間:%@ 秒",videoM.length];
//2.4 設(shè)置圖標
NSURL *url = [NSURL URLWithString:[BaseURL stringByAppendingPathComponent:videoM.image]];
[cell.imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"Snip20200808_28"]];
NSLog(@"%@",videoM.ID);
//3.返回cell
return cell;
}
#pragma mark --------------------
#pragma mark UITableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//1.拿到該cell對應的數(shù)據(jù)
ZBVideo *videoM = self.videos[indexPath.row];
//播放該cell對應的視頻
NSString *urlStr = [BaseURL stringByAppendingPathComponent:videoM.url];
//2.創(chuàng)建視頻播放控制器
MPMoviePlayerViewController *vc = [[MPMoviePlayerViewController alloc]initWithContentURL:[NSURL URLWithString:urlStr]];
//3.彈出控制器
[self presentViewController:vc animated:YES completion:nil];
}
@end