IOS 开发之网络数据下载和JSON解析

简介

  在本文中,我将给大家介绍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数据的解析都是重点,实现的关键

 

 

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。