NSURLConnection資料解析
在網路開發中,從伺服器獲取的二進位制資料包括:
> 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:0 timeoutInterval: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:0 error: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的錯誤。
* 反序列化
> id result = [[JSONDecoder decoder] objectWithData:data];
使用程式碼和測試如下:
int largeNumber = 100 * 1000;
- (void)loadData{
// 建立 url
NSURL *url = [NSURL URLWithString:@"http://localhost/demo.json"];
// 建立請求物件
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval: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 (int index = 0; index < largeNumber; index ++) {
// NSMutableDictionary *result = [[JSONDecoder decoder] objectWithData:data];
NSMutableDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error: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:0 timeoutInterval: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:錯誤資訊
*/
id result = [NSPropertyListSerialization propertyListWithData:data options:0 format:NULL error: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:0 timeoutInterval: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];
} else if(![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 {
int len = self.length.intValue;
return [NSString stringWithFormat:@"%02d:%02d:%02d", len / 3600, (len % 3600) / 60, (len % 60)];
}
# 方式二:
- (void)setLength:(NSNumber *)length {
_length = length;
int len = 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:self action:@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 了
}
2、NSNumber,id屬性
> 程式碼演示實際開發中不用NSNumber帶來的問題。
> 程式碼演示伺服器返回資料中有id鍵值對的問題。
相關文章
- NSURLSession和NSURLConnectionSession
- iOS-->有關NSURLConnectioniOS
- 資料解析
- iOS中的網路--NSURLConnectioniOS
- XML資料解析XML
- datatable資料解析
- Godot 解析資料Go
- Flutter 之資料解析Flutter
- json資料解析JSON
- SQLServer效能資料解析SQLServer
- oracle 資料泵解析Oracle
- 大檔案斷點下載(NSURLConnection)斷點
- iOS開發NSURLConnection 斷點續傳iOS斷點
- 大資料概念:史上最全大資料解析大資料
- Flutter資料解析Map格式Flutter
- 解析大資料json大資料JSON
- GEOJSON資料格式解析JSON
- iOS資料解析框架搭建iOS框架
- 巧用xmltype解析clob資料XML
- ODP資料的解析程式
- day9資料解析
- 如何解析 Ethereum 資料:讀取 LevelDB 資料
- 如何全面解析資料並創造資料故事
- Cephfs資料池資料物件命名規則解析物件
- 在不同的資料庫中解析SQLServer資料資料庫SQLServer
- Oracle資料庫資料鎖機制解析(zt)Oracle資料庫
- 翻出來了 老東西了 , oracle 資料庫解析 extent 資料結構解析Oracle資料庫資料結構
- NSURLConnection類實現下載網路圖片
- iOS開發 GET、POST請求方法:NSURLConnection篇iOS
- 寶付大資料分析解析大資料
- 解析資料踩過的坑
- ORACLE 資料塊格式深入解析Oracle
- 從資料角度解析福州美食
- iOS介面資料解析問題iOS
- DBLP資料集python解析Python
- GPS(NMEA)資料解析
- android JSON解析資料-解析天氣預報AndroidJSON
- abp一代資料遷解析