D15:网络下载(NSURLConnection实现下载, 结合UITableView显示)

网络请求:

  1. http协议了解

  2. 客户端发送请求信息(GET)

  3. 服务器根据网络链接, 找到对应的相应方法, 去服务器的数据库查找数据

  4. 客户端就可以接收到返回的数据,就可以处理数据

  5. JSON/XML处理数据

JSON/XML技术: 手机开发 web开发 服务器开发

  1. http参数怎么传递(GET)

http://open.qyer.com/lastminute/get_lastminute_list?client_id=qyer_ios&client_secret=cd254439208ab658ddf9&v=1&track_user_id=&track_deviceid=E57D6014-1D9F-437C-B9E5-17CF697370FA&track_app_version=5.4.4&track_app_channel=App%20Store&track_device_info=iPhone7,1&track_os=ios%208.1&lat=40.033568&lon=116.358971&app_installtime=1421832230&page_size=20&is_show_pay=1&country_id=0&continent_id=0&max_id=0&times=&product_type=0

1. http -> http协议  
2. open.qyer.com ->公司的服务器域名  
3. lastminute/get_lastminute_list -> 服务器程序唯一对应一个方法  
4. ?是来分隔前面的请求方法和后面的参数的  
5. ?后面的内容都是GET请求的参数信息  
6. client_id=qyer_ios:键值对的方式, client_id是参数名, 类似于函数的形参, qyer_ios是参数值,类似于函数的实参      

同步: 所有事情都是按照先后顺序来做(效率比较低, 阻塞主线程)
异步: 所有事情都是同时进行(效率比较高)


目录

一. NSURLConnection实现网络下载

二. 根据城觅首页的接口, 实现下载, 显示数据

  1. 创建导航视图控制器, 创建表格视图TabelView
  2. 网络下载数据, 遵守协议NSURLConnectionDelegate, NSURLConnectionDataDelegate
  3. 用下载并解析好的数据创建数据源(使用KVC设置属性值, 所以模型中要重写- (void)setValue:(id)value forUndefinedKey:(NSString *)key)
  4. 自定义Cell(如果使用Xib的方式的话, 一定要在在.xib文件中设置重用标签), 注册Cell, 实现UITableView的相关协议方法返回Cell等
  5. 因为网络数据是异步下载的, 因此在成功下载数据创建数据源后需要刷新表格

三. 爱限免的首页

  1. 新建UITabBarController的子类和5个视图控制器的类
  2. 在新建的UITabBarController的子类中创建需要其管理的5个视图控制器
  3. 设置LimitFreeController的导航条
  4. 下载数据创建表格视图UITableView对象, 实现下载数据的代理方法(表格视图的代理方法略)
  5. 创建模型类, 完成自定义Cell
  6. 处理下载数据创建数据源
  7. 实现UITableView的相关代理方法, 返回行数, 设置cell高度, 返回cell

一. NSURLConnection实现网络下载

二. 根据城觅首页的接口, 实现下载, 显示数据

NSURLConnection是系统实现网络请求的方式

目标: 实现下图效果

实现如图效果
  1. 创建导航视图控制器, 创建表格视图TabelView
  2. 网络下载数据, 遵守协议NSURLConnectionDelegate, NSURLConnectionDataDelegate

NSURLConnectionDelegate 下载是否成功等信息
NSURLConnectionDataDelegate 处理返回的数据

1. 定义属性: 网络请求  

@property (nonatomic, strong) NSURLConnection *conn;
2. 下载数据
- (void)downloadData
{
// 1.创建NSURL对象
NSURL *url = [NSURL URLWithString:kHomeUrl];
// 2.创建NSURLRequest类型的对象
NSURLRequest request = [NSURLRequest requestWithURL:url];
// 3.创建NSURLConnection类型的对象, 会自动发送网络请求
/

第一个参数: 请求对象
第二个参数: 代理
*/
_conn = [NSURLConnection connectionWithRequest:request delegate:self];
}
3. 接收下载数据并解析下载数据
* 定义属性来接收下载的数据
@property (nonatomic, strong) NSMutableData *receiveData;
* 判断是否下载成功, 如果服务器响应, 对下载数据进行接收解析

        1. 如果下载失败执行此方法

                - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
                {
                    NSLog(@"%@", error);
                }
            
        2.  网络成功被服务器处理  

                // 返回响应信息
                - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
                {
                    // 返回的响应体
                    NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
                    
                    NSDictionary *dict = res.allHeaderFields;
                    NSLog(@"%@", dict);
                    
                    // 响应的状态码
                    // 200: 正常返回
                    // 404: 客户端程序错误
                    // 400: 客户端的其它错误
                    // 500: 服务器的错误
                    NSInteger code = res.statusCode;
                    NSLog(@"%ld", code);
                    
                    // 清空下载回来的数据
                    [self.receiveData setLength:0];
                }
            
        3. 接收下载数据  

                // 通常下载的数据量会比较大, 会将数据分批下载
                // 每一次下载回来都会调用这个方法
                - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
                {
                    // 存储下载回来的数据
                    // 每次下载的数据都在data这个形参中
                    [_receiveData appendData:data];
                }
            
        4. 下载结束时调用的代理方法  

                // 前面的代理方法都是异步调用的, 这个代理方法会将程序返回主线程
                - (void)connectionDidFinishLoading:(NSURLConnection *)connection
                {
                    // 下载结束, 处理数据
                    
                    // JSON解析
                    id result = [NSJSONSerialization JSONObjectWithData:self.receiveData options:NSJSONReadingMutableContainers error:nil];
                    
                    if ([result isKindOfClass:[NSDictionary class]]) {
                        NSDictionary *dict = result;
                        NSLog(@"%@", dict);
                    }
                }  
  1. 用下载并解析好的数据创建数据源(使用KVC设置属性值, 所以模型中要重写- (void)setValue:(id)value forUndefinedKey:(NSString *)key)
     // 下载结束时调用的代理方法
     // 前面的代理方法都是异步调用的, 这个代理方法会将程序返回主线程
     - (void)connectionDidFinishLoading:(NSURLConnection *)connection
     {
         // 下载结束, 处理数据
         
         // JSON解析
         id result = [NSJSONSerialization JSONObjectWithData:self.receiveData options:NSJSONReadingMutableContainers error:nil];
         
         if ([result isKindOfClass:[NSDictionary class]]) {
             NSDictionary *dict = result;
             NSArray *sectionArray = dict[@"sectioninfo"];
             
             for (NSDictionary *sectionDict in sectionArray) {
                 DataModel *model = [[DataModel alloc] init];
                 // KVC设置属性值
                 [model setValuesForKeysWithDictionary:sectionDict];
                 [self.dataArray addObject:model];
             }
         }
     }
    
  2. 自定义Cell(如果使用Xib的方式的话, 一定要在在.xib文件中设置重用标签), 注册Cell, 实现UITableView的相关协议方法返回Cell等
重用标签
  1. 因为网络数据是异步下载的, 因此在成功下载数据创建数据源后需要刷新表格
     // 下载结束时调用的代理方法
     // 前面的代理方法都是异步调用的, 这个代理方法会将程序返回主线程
     - (void)connectionDidFinishLoading:(NSURLConnection *)connection
     {
         // 下载结束, 处理数据
         ……………………………………………………………………………………
         [self.tbView reloadData];
     }
    

三. 爱限免的首页

最终效果图
  1. 新建UITabBarController的子类和5个视图控制器的类
如图
  1. 在新建的UITabBarController的子类中创建需要其管理的5个视图控制器
     - (void)createViewControllers
     {
         // 视图控制器
         NSArray *ctrlArray = @[@"LimitFreeController", @"ReduceController", @"FreeController", @"SubjectController", @"HotController"];
         // 文字
         NSArray *titleArray = @[@"限免", @"降价", @"免费", @"专题", @"热榜"];
         // 图片
         NSArray *imageArray = @[@"tabbar_limitfree", @"tabbar_reduceprice", @"tabbar_appfree", @"tabbar_subject", @"tabbar_rank"];
         // 选中时的图片
         NSArray *selectImageArray = @[@"tabbar_limitfree_press", @"tabbar_reduceprice_press", @"tabbar_appfree_press", @"tabbar_subject_press", @"tabbar_rank_press"];
     
         NSMutableArray *array = [NSMutableArray array];
         for (int i = 0; i < ctrlArray.count; i++) {
             // 类名
             NSString *name = ctrlArray[i];
             Class cls = NSClassFromString(name);
             UIViewController *ctrl = [[cls alloc] init];
             
             // 文字
             ctrl.tabBarItem.title = titleArray[i];
             // 图片
             ctrl.tabBarItem.image = [UIImage imageNamed:imageArray[i]];
             // 选中时的图片
             ctrl.tabBarItem.selectedImage = [UIImage imageNamed:selectImageArray[i]];
             
             // 添加导航
             UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:ctrl];
             // 添加到数组中
             [array addObject:navCtrl];
         }
         self.viewControllers = array;
     }
    
    • 快速新建不同类名的对象

      NSArray **ctrlArray = @[@"LimitFreeController", @"ReduceController", @"FreeController", @"SubjectController", @"HotController"];
      for (int i = 0; i < ctrlArray.count; i++) {
      // 类名
      NSString *name = ctrlArray[i];
      Class cls = NSClassFromString(name);
      UIViewController *ctrl = [[cls alloc] init];
      }

  2. 设置LimitFreeController的导航条
     - (void)configNavBar
     {
         // 设置导航栏背景图片
         // 图片拉伸 上下不拉伸 左边5个点不拉伸
         [self.navigationController.navigationBar setBackgroundImage:[[UIImage imageNamed:@"navigationbar"] stretchableImageWithLeftCapWidth:5 topCapHeight:0] forBarMetrics:UIBarMetricsDefault];
         
         // 导航栏中间文字
         self.title = @"限免";
         // 导航条标题文字颜色
         // 6个十六进制位表示颜色
         // #000000 ~ #FFFFFF
         [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:30.0f/255.0f green:60.0f/255.0f blue:113.0f/255.0f alpha:1.0f], NSFontAttributeName:[UIFont systemFontOfSize:24]}];
         
         // 左右按钮
         UIButton *leftBtn = [UIButton buttonWithType:UIButtonTypeCustom];
         leftBtn.frame = CGRectMake(0, 0, 60, 36);
         [leftBtn setBackgroundImage:[UIImage imageNamed:@"buttonbar_action"] forState:UIControlStateNormal];
         [leftBtn setTitle:@"分类" forState:UIControlStateNormal];
         [leftBtn setTitleColor:[UIColor cyanColor] forState:UIControlStateNormal];
         [leftBtn addTarget:self action:@selector(gotoCategory:) forControlEvents:UIControlEventTouchUpInside];
         self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:leftBtn];
         
         UIButton *rightBtn = [UIButton buttonWithType:UIButtonTypeCustom];
         /*
         ………………………………………………………………………………………………………………………………………………………………………………
          */
     }
    
    • 图片拉伸 上下不拉伸 左边5个点不拉伸

    UIImage *image = [imageTemp stretchableImageWithLeftCapWidth:5 topCapHeight:0];

    • 设置导航条中间标题文字颜色和字体

    [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor colorWithRed:30.0f/255.0f green:60.0f/255.0f blue:113.0f/255.0f alpha:1.0f], NSFontAttributeName:[UIFont systemFontOfSize:24]}];`
    * 正确显示TabBar上的小图标

     > // 图片  
     ctrl.tabBarItem.image = [[UIImage imageNamed:imageArray[i]] **imageWithRenderingMode:**UIImageRenderingModeAlwaysOriginal];  
     // 选中时的图片  
     ctrl.tabBarItem.selectedImage = [[UIImage imageNamed:selectImageArray[i]] **imageWithRenderingMode:**UIImageRenderingModeAlwaysOriginal];
    
  3. 下载数据创建表格视图UITableView对象, 实现下载数据的代理方法(表格视图的代理方法略)
    1. 新建属性

       @property (nonatomic, strong) UITableView *tbView;
       @property (nonatomic, strong) NSMutableArray *dataArray;
       // 下载的数据
       @property (nonatomic, strong) NSMutableData *receiveData;  
      
    2. 下载数据
      - (void)downloadData
      {
      NSURLConnection *conn = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:kUrl]] delegate:self];
      // 遵守协议, 实现方法
      }

    3. 创建表格视图, 代理方法略
      - (void)createTableView
      {
      // 导航下面
      self.automaticallyAdjustsScrollViewInsets = NO;

           _tbView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 375, 667-64-49) style:UITableViewStylePlain];
           _tbView.delegate = self;
           _tbView.dataSource = self;
           [self.view addSubview:_tbView];
       }
      
    4. NSURLConnection协议方法

       // 下载失败 
       - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
       {
           NSLog(@"%@", error);
       }
       
       // 网络请求返回
       - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
       {
           // 清空以前的数据
           [self.receiveData setLength:0];
       }
       
       // 每次下载数据返回
       - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
       {
           [self.receiveData appendData:data];
       }
       
       // 下载结束调用
       - (void)connectionDidFinishLoading:(NSURLConnection *)connection
       {
           
       }
      
  4. 创建模型类, 完成自定义Cell
    • Cell中的- (void)showData:(LimitFreeModel *)model row:(NSInteger)row方法
      - (void)showData:(LimitFreeModel *)model row:(NSInteger)row
      {
      // 背景图片
      if (row % 2 == 0) {
      self.bgImageView.image = [UIImage imageNamed:@"cate_list_bg1"];
      } else {
      self.bgImageView.image = [UIImage imageNamed:@"cate_list_bg2"];
      }

            // 左边图片
            [self.leftImageView sd_setImageWithURL:[NSURL URLWithString:model.iconUrl]];
            // 名称
            self.nameLabel.text = model.name;
            // 时间
            self.timeLabel.text = model.releaseDate;
            
            // 星级
            CGRect frame = self.starImageView.frame;
            frame.size.width = (model.starCurrent.floatValue / 5) * frame.size.width;
            self.starImageView.frame = frame;
            // 停靠模式
            self.starImageView.contentMode = UIViewContentModeLeft;
            self.starImageView.clipsToBounds = YES;
            
            // 价格
            self.priceLabel.text = model.lastPrice;
            // 类型
            self.typeLabel.text = model.categoryName;
            // 分享
            self.shareLabel.text = [NSString stringWithFormat:@"分享:%@", model.shares];
            // 收藏
            self.favouritesLabel.text = [NSString stringWithFormat:@"收藏:%@",model.favorites];
            // 下载
            self.downloadLabel.text = [NSString stringWithFormat:@"下载:%@",model.downloads];
        }  
      
    • .xib中除了连线以外, 勿忘设置cell的重用标签

      cell的重用标签
  5. 处理下载数据创建数据源
    • 在NSURLConnectionDataDelegate协议的- (void)connectionDidFinishLoading:(NSURLConnection *)connection方法中用下载数据创建数据源
      - (void)connectionDidFinishLoading:(NSURLConnection *)connection
      {
      // 处理下载数据
      // JSON解析
      id result = [NSJSONSerialization JSONObjectWithData:self.receiveData options:NSJSONReadingMutableContainers error:nil];
      if ([result isKindOfClass:[NSDictionary class]]) {
      NSDictionary *dict = result;

                NSArray *appArray = dict[@"applications"];
                for (NSDictionary *appDict in appArray) {
                    // 创建模型对象
                    LimitFreeModel *model = [[LimitFreeModel alloc] init];
                    // kvc
                    [model setValuesForKeysWithDictionary:appDict];
                    // 添加到数组
                    [self.dataArray addObject:model];
                }
                // 刷新表格
                [self.tbView reloadData];
            }
        }
      
  6. 实现UITableView的相关代理方法, 返回行数, 设置cell高度, 返回cell

推荐阅读更多精彩内容