网络(详解)

1.网络涉及到的基本概念

①客户端 : 移动应用/桌面应用
②服务端 : 为客户端提供服务,提供数据和资源的机器。
③请求,响应,数据库服务器等

服务器按开发阶段来划分:

  • 1)远程服务器(外网服务器/正式服务器)
    应用上线后使用的服务器,供全体用户使用,速度取决于服务器性能和用户网速 。

  • 2)本地服务器(内网服务器/测试服务器)
    应用处于开发测试阶段使用的服务器,供开发人员和测试人员使用,属于局域网,速度快,开发效率高。

2.如何找到服务器获取所需资源

途径: URL(Uniform Resoure Locator:统一资源定位器)
基本URL: 协议、服务器名称(或IP地址)、路径和文件名,如“协议://IP地址/路径”

注意:不同的协议,代表着不同的资源查找方式,资源传输方式
基本通信过程:客户端发请求给服务器,服务器接收到请求之后响应

常见协议如下:

①http协议
            概念:超文本传输协议,访问的是远程的网络资源,是网络开发中最常用的协议
            格式:http://
            优点: 1)简单快速(协议简单,服务器端程序规模小,通信速度快) 2)灵活(允许传输各种数据)
            注意:1.1之前版本是非持续连接的


②file协议
              概念:访问的是本地计算机上的资源 (可以省略主机地址)
              格式:file://

③mailto协议
              概念:访问的是电子邮件的地址
              格式:mailto:

④FTP协议
              概念:访问的是共享主机上的资源 
              格式:ftp://

注意:

  • 我们使用的网络是在TCP/IP协议簇上运作的,而Http属于他内部的一个子集
  • TCP协议簇中最重要的一点就是分层设计(OSI规定7层,实际只有4层)
Snip20170208_4.png

这里我主要讲Http协议(请求网络资源)
1.Http通信大致可以分为两大步骤:

请求:客户端向服务器索要数据
响应:服务器返回客户端相应的数据

注意:
①发送请求的时候把请求头和请求体(请求体是非必须的)包装成一个请求对象
②服务器端对请求进行响应,在响应信息中包含响应头和响应体,响应信息是对服务器端的描述,
具体的信息放在响应体中传递给客户端
③网络请求返回的常见状态码

【200】:请求成功
【400】:客户端请求的语法错误,服务器无法解析
【404】:无法找到资源,客户端原因
【500】:服务器内部错误,无法完成请求
  小结:状态码中4开头的是客户端原因;5开头的是服务器原因

④发送请求的URL如果包含中文,发送请求前需要进行转码处理(注意浏览器的URL内部已经做了转码处理)
iOS中如何对URL进行转码:stringByAddingPercentEscapesUsingEncoding (NSUTF8StringEncoding)

2 Http请求方法: get, post, put, head, delete, options, trace,connect,patch, copy, lock, mkcol, move等

常见GET和POST请求的对比 :

  • GET请求参数直接跟在URL后面
  • POST请求的参数放在请求体中
    建议:【除简单数据查询使用GET外,其它的一律使用POST请求】

3.iOS中发送HTTP请求的方案

1)苹果原生
                  ①NSURLConnection    03年推出的古老技术
                  ②NSURLSession       13年推出iOS7之后,以取代NSURLConnection
                  ③CFNetwork              底层技术、C语言的

2)第三方框架
                  ①ASIHttpRequest    (可惜已经停止更新)
                  ②AFNetworking       (主流)
                  ③MKNetworkKit

4.iOS 中发送http网络请求方案实战(原生)

NSURLConnection

使用步骤:
①确定好请求方式 :GET/POST(前者创建的是不可变请求对象,后者创建可变请求对象)
②确定好同步请求还是异步请求(开发中常见为异步请求)

1.NSURLConnection发送GET请求

①发送同步请求
-(void)sendSyncNetwork{    
  //1 创建不可变请求对象
  NSURL *url = [NSURL   URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520&type=JSON"];    
  NSURLRequest *request = [NSURLRequest requestWithURL:url];      
 //2 使用NSURLConnection发送同步请求
  NSURLResponse *response = nil;    
  NSError *error = nil;    
  NSData *data = [NSURLConnection sendSynchronousRequest:request
                                       returningResponse:&response error:&error];      
 //3 解析服务器返回的数据
  NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);}

②发送异步请求(2种,block和代理)
1)block
-(void)sendAsyncNetwork{      
 //1 创建请求对象
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];    
NSURLRequest *request = [NSURLRequest requestWithURL:url];   

 //2发送异步请求
/*     第一个参数:请求对象    
       第二个参数:操作队列->(线程) 决定completionHandler回调在哪个线程中处理(主队列-主线程)     
       第三个参数:completionHandler回调 完成之后的回调    
      response:响应头信息               
      data:响应体信息              
     connectionError:错误信息     
*/
  [NSURLConnection sendAsynchronousRequest: request queue[[NSOperationQueue alloc]init] 
                         completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {        
          //3 解析服务器返回的数据
           NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);   
   }];
}

2)代理
-(void)sendAsyncNetworkDelegate
{
    //1 创建请求对象
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];   
    NSURLRequest *request = [NSURLRequest requestWithURL:url]; 
    //2 设置代理 发送网络请求
  //NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:request delegate:self];     
  //设置代理的第二种方法 startImmediately是否要马上发送请求
    NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO];  
   //发送请求
    [connect start];//此方式仅仅当选择的是不立即发送请求时,当后面需要发送请求时才需要使用。
}
#pragma mark NSURLConnectionDataDelegate
//01 接受到响应(一次)
-(void)connection:(NSURLConnection *)connection didReceiveResponse: (NSURLResponse *)response{    
    NSLog(@"didReceiveResponse");
 }
  //02 接收到服务器返回的数据(多次)
-(void)connection:(NSURLConnection *)connection 
   didReceiveData:(NSData *)data{   
   NSLog(@"didReceiveData--%zd",data.length);//最终数据长度   
   [self.resultData appendData:data];  
 }
  //03 失败
-(void)connection:(NSURLConnection *)connection 
 didFailWithError:(NSError *)error{    
    NSLog(@"didFailWithError");
}
  //04 完成之后
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{ 
   NSLog(@"connectionDidFinishLoading");      
   //解析服务器返回的数据   
 NSLog(@"%@",[[NSString alloc]initWithData:self.resultData   encoding:NSUTF8StringEncoding
  ]);
}

2.NSURLConnection发送POST请求 (这里只讨论主流:异步 + block )

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{  

    //1创建可变请求对象(因为默认发送GET)
    NSURL *url = [NSURL  URLWithString:@"http://120.25.226.186:32812/login"];   
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];       //+ 修改请求方法为POST
    request.HTTPMethod = @"POST";       
  //+ 设置参数(请求体)
 //username=520it&pwd=520it&type=JSON   
     request.HTTPBody  = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];  

     //2 发送异步请求
     [NSURLConnection sendAsynchronousRequest:request 
                                        queue:[NSOperationQueue alloc] init] 
                            completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError)   {              
        //3 解析服务器返回的数据
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);   }];
}

3.NSURLConneection与Runloop补充

①设置代理的方法中,如果立即发送请求,那么内部会自动将connect作为一个source添加到runloop中
②设置代理的方法中,如果设置为NO不立即发送请求,那么内部不会添加connect到runloop中,需调用start方法才会添加,调用start那么start内部会把当前的connect添加到runloop并且设置模式为默认,子线程中运行循环不存在,那么会主动创建。

注意:如果在子线程中发送网络请求,则子线程的runloop需要手动创建并开启,才能处理任务。

NSURLSession

1.使用步骤:
①创建NSURLSession对象(单例对象 或 自定义Session对象【调用类方法设置代理】)
②创建task (NSURLSessiontask是个抽象类,必须使用它的子类)
②执行task (resume)

Snip20170208_5.png

2.开发实战

方案一: 通过Block 回调响应体

-(void)getData
{

    //1.创建会话对象
  NSURLSession *session = [NSURLSession sharedSession];
   //2.根据会话对象创建Task(请求任务)
  NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"];  
  NSURLRequest *request = [NSURLRequest requestWithURL:url]; 
 //灵活多变,可变请求对象则可以为POST
 NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request 
                                             completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

      //注意:创建任务时还可以dataTaskWithURL ,则请求方式只能是GET     
     //解析服务器返回的数据       
     NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);       
     NSLog(@"%@",[NSThread currentThread]);//默认completionHandler在子线程中执行
}];       
    //3.执行Task(发送请求)
    [dataTask resume];
}

注意: 简便方式如下:

-(void)getData{   
   [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/loginusername=520it&pwd=520it&type=JSON"] 
                                completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {              
         //解析数据       
         NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);      
       }] resume];
 }

方案二:通过代理获得响应体

-(void)delaget{  

 //1.创建会话对象 设置代理
/*    
    第三个参数:队列->线程(代理方法在哪个线程中执行)|如果该参数传递nil 那么在子线程中执行(默认)   
*/   
   NSURLSession *session = [NSURLSession sessionWithConfiguration:
  [NSURLSessionConfiguration defaultSessionConfiguration] delegate: self 
                                                     delegateQueue:nil];      
  //2.创建请求任务 (这里举例POST请求)
  NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"]; 
  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];    
  request.HTTPMethod = @"POST";  
  request.HTTPBody = [@"username=520it&pwd=520it&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];   
  NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];      
   //3.执行Task
  [dataTask resume];
}

#pragma mark NSURLSessionDataDelegate
//01 接收到服务器响应的时候调用
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask 
                                didReceiveResponse:(NSURLResponse *)response 
                                 completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{   
          NSLog(@"didReceiveResponse---%@",[NSThread currentThread]);//子线程   
         self.resultData = [NSMutableData data]; //tips   
         //需要告诉系统是否接收服务器返回的数据 
          completionHandler(NSURLSessionResponseAllow
    );
}
//02 接受到服务器返回数据的时候调用 (可能被调用多次)
-(void)URLSession:(NSURLSession *)session 
         dataTask:(NSURLSessionDataTask *)dataTask 
   didReceiveData:(NSData *)data{    
  //拼接服务器返回的数据   
   [self.resultData appendData:data];
}
//03 请求完成或者是失败的时候调用
-(void)URLSession:(NSURLSession *)session
             task:(NSURLSessionTask *)task 
 didCompleteWithError:(NSError *)error{   
   //解析服务器返回的数据 
     NSLog(@"%@",[[NSString alloc]initWithData:self.resultData encoding:NSUTF8StringEncoding]);
}

3.实战总结

①创建Task的方法中如果需要传入“请求对象”,那么请求方式的方式可以是GET/POST,具体取决于你。反之方法参数直接传URL,那么请求方式只能是GET(因为没有单独的请求体)
②如果是想利用block发送请求Task,则利用sharedSession创建单例会话对象;反之利用代理方法,则自定义会话对象

5.数据解析

1.须知: 服务器返回给客户端的数据一般都是JSON格式或者XML格式(文件下载除外)

2.数据格式介绍:

①JSON

1)JSON是一种轻量级的数据格式,一般用于数据交互
2)JSON的格式很像OC中的字典和数组

 {"name" : "jack", "age" : 10}
 {"names" : ["jack", "rose", "jim”]}

3)标准JSON格式的注意点:key必须用双引号
4)JSON 与OC 对照表

               JSON                 OC
             大括号 { }              NSDictionary
            中括号 [ ]              NSArray
            双引号 " "              NSString
            数字 10、10.8            NSNumber
在iOS中,JSON的常见解析方案有4种:

第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差)
苹果原生(自带):NSJSONSerialization(性能最好)

NSJSONSerialization的常见方法:

  • JSON数据 -> OC对象 (反序列化,得到OC的字典或数组 => 模型 故常用)

    +(id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
    
  • OC对象  -> JSON数据 (序列化)

    +(NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
    
②XML

1)全称是Extensible Markup Language,译作“可扩展标记语言”。跟JSON一样,也是常用的一种用于交互的数据格式
一般也叫XML文档(XML Document)

  1. 一个常见的XML文档一般由以下三部分组成
  • 文档声明
  • 元素(Element)
  • 属性(Attribute

XML语法 – 文档声明
在XML文档的最前面,必须编写一个文档声明,用来声明XML文档的类型

最简单的声明:
                     <?xml version="1.0" ?>
                   用encoding属性说明文档的字符编码
                    <?xml version="1.0" encoding="UTF-8" ?>

XML语法 – 元素(Element)

①一个元素包括了开始标签和结束标签
                  拥有内容的元素:        <video>哈哈</video>
                  没有内容的元素:        <video></video>
                  没有内容的元素简写:  <video/> 

②一个元素可以嵌套若干个子元素(不能出现交叉嵌套)
                            <videos>
                                    <video>
                                            <name>小黄人 第01部</name>
                                         <length>30</length>
                                    </video>
                            </videos>

③规范的XML文档最多只有1个根元素,其他元素都是根元素的子孙元素

           XML语法 –元素的注意:   XML中的所有空格和换行,都会当做具体内容处理         
                
            故下面两个元素的内容是不一样的
                    第1个
                                <video>小黄人</video>

                    第2个
                                <video>
                                    小黄人
                                </video>

XML语法 – 属性(Attribute)

①一个元素可以拥有多个属性
                       <video name="小黄人 第01部" length="30" />
                       video元素拥有name和length两个属性

②属性值必须用 双引号"" 或者 单引号'' 括住

③实际上,属性表示的信息也可以用子元素来表示,比如
                        <video>
                                <name>小黄人 第01部</name>
                                <length>30</length>
                        </video>
XML解析

1.须知:XML的解析方式有2种

  • DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
  • SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件

2.iOS中的XML解析方式:
①苹果原生
NSXMLParser:SAX方式解析,使用简单,文件大小通吃
②第三方框架
libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
GDataXML:DOM方式解析,由Google开发,基于libxml2

3.XML解析方式的选择建议
大文件:NSXMLParser、libxml2
小文件:GDataXML、NSXMLParser、libxml2

注意:相比之下,JSON的体积小于XML,所以服务器返回给移动端的数据格式以JSON居多

6.数据解析实战

1.复杂JSON解析

1.解析步骤:

①确定服务器返回给客户端的数据是数组还是字典亦或是其他:直接百度json在线格式化或者把JSON数据写plist文件再观察
②. 一般反序列化成OC对象(字典或数组)再面向模型开发

2.经验总结:
①反序列化(JSON -> OC对象)方法中,options参数不能乱填 (=> 确定响应体类型很重要!!!)
NSJSONReadingMutableContainers = (1UL << 0), 是可变的
NSJSONReadingMutableLeaves = (1UL << 1), 得到的字典中所有的string都是可变的
NSJSONReadingAllowFragments = (1UL << 2) 当最外层既不是字典也不是数组的时候必须使用该枚举
id obj = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
注意:kNilOptions 表示0 默认的意思

②并不是所有的对象都可以序列化
1)最外层的对象必须是 NSArray or NSDictionary里面所有的对象都只能是 NSString, NSNumber, NSArray, NSDictionary, or NSNull
2)所有字典的keys are NSStrings
3)NSNumbers 必须是合法并且不能是无穷大
故 保险起见,序列化之前会进行判断一下是否可以序列化

if(![NSJSONSerialization isValidJSONObject:array])
{
    NSLog(@"该对象不支持序列化处理");
    return;
}

③json文件中的数据为NSData,不能通过字典获取

//NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] 
                                                  pathForResource:@"test.json" ofType:nil]];
NSData *jsonData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] 
                                  pathForResource:@"test.json" ofType:nil]];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:nil];

④在将JSON数据写入文件的时候,一般会对JSON数据进行排版

//JSON -->OC对象  反序列化处理
id obj = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSLog(@"%@--%@",[obj class],obj);
    
//对json数据进行排版
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:obj options:NSJSONWritingPrettyPrinted error:nil];
    
 //写json数据
[jsonData writeToFile:@"/Users/wuyuanping/Desktop/test.json" atomically:YES];

⑤面向模型开发会存在的问题【容易出错|重命名|关键字等】
服务器返回的数据很多,我们只要一部分 => 可能并不能直接使用KVC
服务器提供的属性名字是关键字 => 需要给属性重新命名
属性过多转换费时且无技术含量 => 一般会用框架字典转模型(或者运行时)

拓展:
1.字典转模型框架:

  • Mantle:需要继承自MTModel
  • JSONModel:需要继承自JSONModel
  • MJExtension:不需要继承,无代码侵入性
  • YYModel :高性能

2.选择和使用框架的注意点:
①侵入性
②易用性,是否容易上手
③可扩展性,很容易给这个框架增加新的功能

MJExtension使用举例:
//1.把字典数组转换为模型数组
    self.videos = [YPVideo objectArrayWithKeyValuesArray:videoArray];

//2.重命名模型属性的名称
//第一种重命名属性名称的方法,有一定的代码侵入性)
//设置字典中的id被模型中的ID替换
+(NSDictionary *)replacedKeyFromPropertyName
{
    return @{
             @"ID":@"id"
             };
}

//第二种重命名属性名称的方法,代码侵入性为零
  [YPVideo setupReplacedKeyFromPropertyName:^NSDictionary *{
    return @{
             @"ID":@"id"
             };
}];

//3.MJExtension框架内部实现原理-运行时
代码示例

1.JSON解析
- (void)viewDidLoad{
[super viewDidLoad];
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=JSON"]
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//输出结果表明:返回的是字典(元素为存放字典的数组)
// NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
//解析服务器返回的数据 JSON-->OC对象(反序列化)
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
//把字典数组->模型数组
NSArray *arrayM = dict[@"videos"];
NSMutableArray *arrM = [NSMutableArray array];
for (NSDictionary *dict in arrayM) {
[arrM addObject:[YPVideo videoWithDict:dict]];
}
self.videos = arrM;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//刷新UI,得跳到主线程中
[self.tableView reloadData];
}];
}] resume];
}

2.XML解析

解析步骤
①创建解析器
②设置代理,遵守代理协议,实现代理方法,在代理方法中解析元素
③开始解析
- (void)viewDidLoad{
[super viewDidLoad];
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/video?type=XML"]
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//01 创建XML解析器
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
//02 设置代理
parser.delegate = self;
//03 开始解析 该方法本身是阻塞
[parser parse]; //跳到他的代理方法
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
//刷新UI
[self.tableView reloadData];
}];
}] resume];
}

#pragma mark NSXMLParserDelegate
//01 开始解析XML文档
-(void)parserDidStartDocument:(NSXMLParser *)parser{    
        NSLog(@"parserDidStartDocument");
}
//02 开始解析文档中某个元素的时候调用 该方法可能会被调用多次
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 
                                        namespaceURI:(NSString *)namespaceURI  
                                       qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{    
        //过滤掉根元素,否则报错
      if ([elementName isEqualToString:@"videos"]) {        return;    }   
     NSLog(@"didStartElement--%@--%@",elementName,attributeDict);
      //检验参数代表什么       
      //每当得到一个字典 就应该转换为模型 并添加到全局的可变数组
      [self.videos addObject:[YPVideo mj_objectWithKeyValues:attributeDict]];
}
//03 某个元素解析完毕的时候调用
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
     namespaceURI:(NSString *)namespaceURI 
     qualifiedName:(NSString *)qName{     
     NSLog(@"didEndElement");
}

//04 整个XML文档解析完毕
-(void)parserDidEndDocument:(NSXMLParser *)parser{   
     NSLog(@"parserDidEndDocument");
}

使用GDataXML解析XML 步骤:

前提:

  • 配置环境 :
    ① 先导入框架 #import "GDataXMLNode.h"
    ② 配置环境(GDataXML框架是MRC的,所以还需要告诉编译器以MRC的方式处理GDataXML的代码)
  • 步骤:

//1.加载XML文档(使用的是DOM的方式一口气把整个XML文档都吞下)

GDataXMLDocument *doc = [[GDataXMLDocument alloc]initWithData:data options:kNilOptions error:nil];

//2.获取XML文档的根元素,根据根元素取出XML中的每个子元素

 NSArray * elements = [doc.rootElement elementsForName:@"video"];

//3. 取出每个子元素的属性并转换为模型

for (GDataXMLElement *ele in elements) {    
    YPVideo *video = [[YPVideo alloc]init];   
    video.name = [ele attributeForName:@"name"].stringValue; 
    video.length = [eleattributeForName:@"length"].stringValue.integerValue; 
    video.url = [ele attributeForName:@"url"].stringValue;   
    video.image = [ele attributeForName:@"image"].stringValue;   
    video.ID = [ele attributeForName:@"id"].stringValue;   

   //4. 把转换好的模型添加到tableView的数据源self.videos数组中
  [self.videos addObject:video];
}

案例 - NSURLSession实现大文件下载

问题解决思路:
①文件下载内存飙升 => 直接将数据写入沙盒 (文件句柄 或者 输出流)
②断点下载 => 设置请求头 (Range)
③离线断点下载 => 代理方法(可以实时将下载数据存入沙盒)
注意:输出流创建文件路径是懒加载,故不论调用几次,只会创建一个文件夹,
对比使用文件句柄指针得要手动控制只创建一个文件夹,轻松不少。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容