標籤:
簡介
在本文中,我將給大家介紹ios中如何運用NSURLConnection從網路上下載資料,以及解析JSON資料格式的資料,還有資料的顯示和圖片非同步下載。
涉及到的知識點:
1.NSURLConnection的非同步下載和資料要求方法的封裝。
2.認識JSON格式和JSON格式的解析使用
3.資料在模擬器上的顯示和圖片的非同步下載(使用SDWebImage非同步顯示圖片,SDWebImage是一個庫)
注意:
在ios開發中,無論是資料還是圖片都是使用非同步下載方法,不能使用同步。
內容
首先,要完成一個項目,你得需要素材,圖片,還有網路介面(網路介面其實就一下載資料的網址URL,因為你的app資料是通過網路從服務端請求過來的)
1.網路下載基礎知識介紹
(1)手機app網路應用
玩過智能手機我們都知道,手機裡的app有本地應用和網路應用,說通俗點本地應用就是不需要網路也能使用,而一般,QQ等需要上網才能使用的就是網路應用,這些網路應用是需要網上下載資料才能啟動並執行。這裡我們只講網路應用。
(2)網路應用的結構程式
分兩種,一種是用戶端,一種是服務端。需要上網下載資料才能使用的網路應用就是用戶端,而為這個網路應用提供資料服務的就是服務端。
(3)常見的網路介面模式
ios網路應用的常見介面一半都是HTTP形式的URL地址,
例如愛限免應用首頁的資料地址為http://iappfree.candou.com:8080/free/applications/limited?currency=rmb&page=1&category_id=
在項目中一般使用一些開源庫(開源庫的時候往後再講)通過這種網址下載資料. 例如AFNetworking
(4)常見資料格式
iOS開發中常見的資料格式有兩種, 一種是JSON格式, 另外種是XML格式, 相對來說, JSON格式使用的比較多
(5)app介面開發的一般流程
ios中開發一個介面,需要介面,介面素材資源,網路介面這三項
開發的流程一般如下:
***1.確定你要開發的步驟,一般可以先擷取資料,即從網路介面中下載資料
***2.然後把你下載的資料(JSON或XML資料)進行解析,建立資料模型model,一般用MVC這樣的設計模式來編程開發
***3.使用UI控制項顯示這些解析後的資料,一般都需要自訂cell顯示
2.具體實現步驟 1.使用非同步下載資料的方法 (NSURLConnection非同步下載)把這個方法封裝起來,以後可以代碼複用
***1.先說普通簡單狀態下的非同步下載,網路介面以這個為例子
http://iappfree.candou.com:8080/free/applications/limited?currency=rmb&page=1&category_id=
[self testNSURLConnectionAsyncDownloadData]; //JSON文法 [self jsonFormat];}-(void)jsonFormat{ //JSON //JavaScript Object Notation /* { "count":20, "data":[ "zhangsan", "lisi", "wangwu" ] } */ //[] 表示數組,對應NSArray //, 表示並列的資料 //{} 表示字典,對應NSDictionary //: 表示索引值對 //"ta" 表示字串,對應NSString //20 對應NSNumber //JSON格式格式化工具 // Jason // Json Editor // 線上: http://www.kjson.com/ }#pragma mark - 非同步下載-(void)testNSURLConnectionAsyncDownloadData{ NSString *urlString = @"http://iappfree.candou.com:8080/free/applications/limited?currency=rmb&page=1&category_id="; //初始化 _data = [[NSMutableData alloc] init]; //發起了一個非同步URL串連請求 //非同步: 執行了方法之後開始下載,立即返回 // 下載過程在後台(多線程)執行 _connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]] delegate:self startImmediately:YES]; NSLog(@"initWithRequest 執行完成"); }
當使用這個方法的時候,下載的過程就在程式後台進行,遵循 NSURLConnectionDataDelegate 這個協議就能調用相關方法了,比如下載完成後執行的方法,從而完成相關操作
***2.下面就是相關方法操作:
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ NSLog(@"接收到那個方法initWithRequest,伺服器響應執行");}//接收到資料就執行這個方法,下載資料-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ [_data appendData:data];}//資料下載完成後使用的方法,直接看英文意思-(void)connectionDidFinishLoading:(NSURLConnection *)connection{ NSString *str = [[NSString alloc]initWithData:_data encoding:NSUTF8StringEncoding]; NSLog(@"列印下載後的資料%@",str); NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:_data options:NSJSONReadingMutableContainers error:nil]; NSLog(@"%@",dic); NSArray *arr = dic[@"applications"]; for (NSDictionary *dic2 in arr) { NSLog(@"name = %@",dic2[@"name"]); }}
2.通過上面那個簡單的例子,我們認識了NSURLConnection非同步下載,接下來就介紹下非同步下載的封裝
***1.建立一個繼承NSObject的類
***2.定義一個儲存資料的屬性和處理這些資料的執行個體方法
#import <Foundation/Foundation.h>@interface ZJHttpRequest : NSObject//儲存下載的資料@property (copy,nonatomic) NSMutableData *data;//作用:傳入網址,下載完成後執行target對象中action方法 類比按鈕,點擊執行事件-(void)requestWithUrl:(NSString *)url target:(id)target action:(SEL)action;@end
***3..m檔案的實現步驟
#import "ZJHttpRequest.h"//消除performSelector的警告#pragma clang diagnostic ignored "-Warc-performSelector-leaks"//類擴充//項目實踐:// 有些執行個體變數內部使用, 不想放在標頭檔中, 放在這兒@interface ZJHttpRequest ()<NSURLConnectionDataDelegate>{ NSURLConnection *_connection; NSString *_url; id _target; SEL _action;}@end@implementation ZJHttpRequest//作用:// 傳入網址, 下載完成執行後執行target對象中action方法-(void)requestWithUrl:(NSString *)url target:(id)target action:(SEL)action{ _url = url; _target = target; _action = action; //發起URL請求 _data = [[NSMutableData alloc] init]; _connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]] delegate:self startImmediately:YES];}-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ [_data appendData:data];}-(void)connectionDidFinishLoading:(NSURLConnection *)connection{ //下載完成了, 執行儲存的方法 if(_target && [_target respondsToSelector:_action]) { [_target performSelector:_action withObject:self]; } }@end
***4.如果不能很好的理解其中每段代碼代表是意思,可以看看下面我的注釋,如果有錯,非常歡迎各位看官的指教
#import "ZJHttpRequest.h"//消除performSelector的警告#pragma clang diagnostic ignored "-Warc-performSelector-leaks"//類擴充//項目實踐://有些執行個體變數內部使用,不想放在標頭檔中,放在這@interface @end之間@interface ZJHttpRequest ()<NSURLConnectionDataDelegate>{ NSURLConnection *_connection; NSString *_url; id _target; SEL _action;}@end@implementation ZJHttpRequest-(void)requestWithUrl:(NSString *)url target:(id)target action:(SEL)action{ _url = url;//把傳過來的參數網址URL,賦給新建立的 NSString *_url對象 _target = target;//傳過來的參數target target QFPXViewController * 0x8cea970 0x08cea970 _action = action;//傳過來的參數action SEL "dealDowloadFinish:" 0x00009a4f _data = [[NSMutableData alloc]init]; //NSURLConnection非同步下載,執行了這個方法就在後台下載了 _connection = [[NSURLConnection alloc]initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]] delegate:self startImmediately:YES];//_connection NSURLConnection * 0x8d79720 0x08d79720 記住,這個是非同步下載,當程式執行了這個方法後,下載資料就變成在後台下載了,(多線程),所以之後requestWithUrl之後就已經在下載資料,然後建立表格,表格則遵循協議,調用那兩個方法,返回資料行數,而在NSURLConnection非同步下載中,也需要遵循協議,就會有你下載了資料後可以執行這個方法didReceiveData //程式走向就是,當在QFPXViewController,執行這個封裝的方法的時候,會把相應的參數傳過來,或者說,在QFPXViewController,調用了封裝的方法,就跑到這個封裝的方法中 --requestWithUrl, //然後,建立表格,而後擷取資料,return _dataArray.count 後就到了下面這裡didReceiveData, }-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ //data __NSCFData * 17088 bytes 0x08d8e140 17088位元組 [_data appendData:data]; //appendData 附加資料 //_data NSConcreteMutableData * 17088 bytes 0x08d67980 _data也得到了這麼多位元組}-(void)connectionDidFinishLoading:(NSURLConnection *)connection{ //接收完資料了,已經下載完成,然後判斷傳過來的target和action這兩個參數有沒有賦給_target和_action,或者說_target和_action是不是空的,一個保障手段方法,如果傳過來了,就符合if判斷語句,則執行裡面的方法,也就是程式的邏輯思維裡,那邊QFPXViewController傳過來兩個參數,然後在這裡封裝的類ZJHttpRequest裡用非同步下載,下載完資料後判斷,是否傳了參數過來,如果不為空白的話就響應執行 //_action帶過來的方法dealDowloadFinish:,也就是再跳到那個類寫的方法裡,處理資料,這就是封裝了方法的一個作用,其實就是非同步請求下載資料,下載後再來個參數判斷,至於下載後的資料處理還是“彷彿“在QFPXViewController中處理,其實只不過是在QFPXViewController中寫處理常式邏輯而已 //self ZJHttpRequest * 0x8c593c0 0x08c593c0 //_target QFPXViewController * 0x8ce52b0 0x08ce52b0 //_action SEL "dealDowloadFinish:" 0x00009a4f //_target是否為空白並且_target能否響應_action if (_target && [_target respondsToSelector:_action]) { //判斷傳過來參數了則執行這裡面帶過來的方法,執行了帶過來的方法dealDowloadFinish,則跳到這個方法裡 [_target performSelector:_action withObject:self];//這段代碼的意思就是讓這個類QFPXViewController 執行perform這個選擇的方法_action(dealDowloadFinish)用這個類self帶的參數 } }@end
這樣,我們就把這個非同步下載的方法封裝好了,下次就直接調用就可以了,引入標頭檔,建立該標頭檔對象,調用封裝的執行個體方法,傳過去參數,執行,並返回執行帶過去處理資料的方法。
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //資料介面 NSString *urlString = @"http://iappfree.candou.com:8080/free/applications/limited?currency=rmb&page=1&category_id="; _dataArray = [[NSMutableArray alloc] init]; //下載 _request = [[ZJHttpRequest alloc] init]; [_request requestWithUrl:urlString target:self action:@selector(dealDowloadFinish:)]; [self createTableView];}
- (void)viewDidLoad{ [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //資料介面 網路介面 NSString *urlStr = @"http://iappfree.candou.com:8080/free/applications/limited?currency=rmb&page=1&category_id="; _dataArray = [[NSMutableArray alloc]init]; //下載 _request = [[ZJHttpRequest alloc]init]; //self self QFPXViewController * 0x8cea970 0x08cea970 //urlStr __NSCFConstantString * @"http://iappfree.candou.com:8080/free/applications/limited?currency=rmb&page=1&category_id=" 0x000106d4 //調用這個ZJHttpRequest類對象的要求方法,方法requestWithUrl已經是類ZJHttpRequest封裝好的,所有,你在這裡self QFPXViewController *調用的話就是把當前的target,action這兩個參數還有網址URL傳入self ZJHttpRequest這個類中 [_request requestWithUrl:urlStr target:self action:@selector(dealDowloadFinish:)]; [self createTabelView]; }
下面是處理資料的方法dealDowloadFinish
//這個方法都相當於放在viewWillAppear裡面了,因為程式的走向是先下面這裡的方法,再給表返回return _dataArray.count;所以重新整理資料就在這裡重新整理-(void)dealDowloadFinish:(ZJHttpRequest *)request{ NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:request.data options:NSJSONReadingMutableContainers error:nil]; // NSLog(@"dic = %@",dic); NSArray *appList = dic[@"applications"]; for (NSDictionary *dic in appList) { AppModel *model = [[AppModel alloc]init]; model.applicationId = dic[@"applicationId"]; model.name = dic[@"name"]; model.iconUrl = dic[@"iconUrl"]; [_dataArray addObject:model]; } [_tabelView reloadData];}
3.來到這裡,就順勢說到JSON資料格式的解析
1.相信解析過JSON資料格式的朋友都知道,就有個Jason軟體非常好用,使用也很簡單
***1.通過網路介面得到未經處理資料,然後全選中這些資料,黏貼到
com+v然後就回彈出這麼個視窗
接著我們點擊左上方的Text就得到我們想要的格式化好後的JSON資料了
4.接下來就是認識學習JSON資料格式,這樣就能完成以後的資料解析操作
[self jsonFormat];}-(void)jsonFormat{ //JSON //JavaScript Object Notation /* { "count":20, "data":[ "zhangsan", "lisi", "wangwu" ] } */ //[] 表示數組,對應NSArray //, 表示並列的資料 //{} 表示字典,對應NSDictionary //: 表示索引值對 //"ta" 表示字串,對應NSString //20 對應NSNumber //JSON格式格式化工具 // Jason // Json Editor // 線上: http://www.kjson.com/ } 5.資料擷取,解析完後就用自訂cell來顯示
1.用的石MVC程式設計模式來實現,建立一個基礎NSObject的資料類和基礎於UITableViewCell的自訂的cell,以下是部分代碼
[self createTabelView]; }-(void)createTabelView{ _tabelView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain]; _tabelView.dataSource = self; _tabelView.delegate = self; [self.view addSubview:_tabelView];}-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ // return _dataArray.count;後返回高度,返回了_dataArray.count次 return 80;}-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return _dataArray.count;}-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *identifer = @"cell"; //資料有10行,但是這裡的判斷顯示是建立了7個cell,顯示6個 AppCell *cell = [tableView dequeueReusableCellWithIdentifier:identifer]; if (cell == nil) { cell = [[AppCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifer]; } AppModel *model = _dataArray[indexPath.row]; //cell.textLabel.text = model.name; cell.nameLabel.text = model.name; [cell.iconImageView setImageWithURL:[NSURL URLWithString:model.iconUrl]]; return cell; }
6.完成
7.圖片的下載實現用的是SDWebImage這個庫裡的方法
1.選擇工程,點Build Phases,搜尋SDW,得到所有sd開頭的檔案
2.全選擇,靠右邊雙擊彈出一個框,輸入-fno-objc-arc,使用這個模式
3.然後再在實現的類下引入標頭檔#import "UIImageView+WebCache.h"
4.最後,用這個方法實現圖片的載入顯示
[cell.iconImageView setImageWithURL:[NSURL URLWithString:model.iconUrl]];
總結:實現一個項目工程,簡單的介面顯示
一.拿到介面素材,網路介面
二.擷取資料,解析資料
三.顯示資料
其中NSURLConnection非同步下載和方法封裝,以及JSON資料的解析都是重點,實現的關鍵
IOS 開發之網路資料下載和JSON解析