zoukankan      html  css  js  c++  java
  • NSURLConnection、NSURLSession

    NSURLConnection
     
    1、准备网络资源地址:URL
    注意:由于URL支持26个英文字母,数字和少数的几个特殊字符. 因此对于URL中包含非标准URL的字符,需要进行编码. iOS提供了函数 stringByAddPercentEscapesUsingEncoding对中文和一些特殊字符进行编码
    2、发送数据请求
    3、遵守协议:<NSURLConnectionDataDelegate>,处理下载任务时的事件
     
    @interface ViewController ()<NSURLConnectionDataDelegate>
    //用于存储网络下载的数据.把分包的数据整合起来.
    @property (nonatomic, strong) NSMutableData *receivedData;

    @end
    //!!请注意URL地址必须包含http等协议的前缀. xcode并不会自动为我们添加.
    //    NSURL OC的URL类型,地址资源定位
        NSURL *url = [NSURL URLWithString:@"http://www.tmooc.cn"];
    // OC的请求类型,包含了请求相关的操作.例如缓存.cookie等等...
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
    //    Immediately 立刻,马上
    //    startImmediately 立刻开始
    //    YES代表立刻开始请求,
    //    NO 不需要立刻开始,需要手动触发.
        NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    //    手动开始请求
        [conn start];
    }
     
    //1、当收到服务器的请求响应,触发此代理
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
        NSLog(@"didReceiveResponse:%@", response);
        _receivedData = [[NSMutableData alloc] init];
    }
    //2、收到服务器传输的数据,如果数据量比较大的话,服务器会分批传,俗称数据包.
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    //    由于data有可能是分批的,所以我们需要一个全局的MutableData去拼接起来
        NSLog(@"didReceiveData:%ld个字节", data.length);
        [_receivedData appendData:data];
    }
    //3、连接成功被加载了
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{
        NSLog(@"connectionDidFinishLoading");
    //    写到沙盒的document文件夹下的baidu文件中
        NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/baidu"];
        NSLog(@"path is %@", path);
    //    data类型转换为字符串,再存储
    //    使用NSUTF8StringEncoding编码类型,对_receivedData这个二进制类型进行转码,转换为字符串
        NSString *baiduStr = [[NSString alloc] initWithData:_receivedData encoding:NSUTF8StringEncoding];
    //    定义一个error指针,不需要初始化
    //    error指针的初始化由下面的方法来完成. 如果有错误就会被赋值. 没错误,依然会是nil
        NSError *error = nil;
        [baiduStr writeToFile:path atomically:NO encoding:NSUTF8StringEncoding error:&error];
        if (error) {
    //        error有值,则说明上面的写文件方法出错了
            NSLog(@"error:%@", error);
        }
    }
     
    //——————————————————--------------------—数据请求的方式----------------------------------------
    //通常我们使用宏定义 或者 static的方式 在文件的顶端,声明文件中需要用到的常量
    //好处:便于维护. 特别是一个常量 要很多个位置使用时
    //习惯上,添加k为前缀
    #define kBaiduURLString    @"http://www.baidu.com"
     
        [selfsendSyncRequest:kBaiduURLString];
     
    异步请求:(在子线程执行)
    - (void)sendAsyncRequest:(NSString *)urlString{
    //转码: 对urlString进行标准化的编码,防止中文和特殊字符的出现
    //    Percent 百分号,分数
        urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSURL *url = [NSURL URLWithString:urlString];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        NSLog(@"主线程是%@", [NSThread mainThread]);
    //异步请求方法:
        [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    //下载结束后的处理:
            NSLog(@"在线程%@中处理",[NSThread currentThread]);
            NSLog(@"接收到%ld字节的数据", data.length);
        }];
    }
     
    同步请求:(不用,在主线程执行)
        urlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSURL *url = [NSURL URLWithString:urlString];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
    //    用于存储服务器返回的响应,参考delegate方式中的didReceiveResponse
        NSURLResponse *response = nil;
        NSError *error = nil;
    //    发送同步请求
        NSTimeInterval beginTime =[NSDate timeIntervalSinceReferenceDate];
        NSData *receivedData =[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
        NSLog(@"接收到%ld个字节的数据", receivedData.length);
        NSTimeInterval endTime = [NSDate timeIntervalSinceReferenceDate];
        NSLog(@"请求耗时%f秒", endTime - beginTime);
    //——————————————————------------------------—End--------------------------------------------
     
    //———————————————————-------------------断点下载----------------------------------------------
    服务器: 被动的角色
    客户端: 主动的角色
    客户端必须告诉服务器当前应该从哪个地方开始继续下载

    如何告诉, 通过http协议的数据包?
    客户端 —http> 服务器
    key(BigFile.zip: 600M):
    1) 客户端Request请求头中Range: bytes=100-200 ;—> 服务器从100bytes开时发送给客户端, 直到200bytes
    2) 客户端Request请求头中Range: bytes=100- ;—> 服务器从100bytes开时发送给客户端, 直到发送完毕为止
    步骤:
    1. 使用NSFileManager在didReceiveResponse方法中创建一个空的文件(在沙盒中的caches路径下),获取文件的总大小
    2. 在didReceiveData方法中: 首先将writeHandler移到文件的最后, 之后再将数据写入文件中.
    3. 在DidFinishLoading方法中, 对属性重新初始化,在关闭文件写句柄
     
    //Caches路径
    @property(nonatomic,strong)NSString *cachePath;
    @property(nonatomic,strong)NSFileHandle *writeHandle;
    @property(nonatomic,assign)long long currentLength;//已下载的文件的大小(以字节为单位)
    @property(nonatomic,assign)long long totalLength;//文件的总大小
    //断点传输
    @property(nonatomic,strong)NSMutableURLRequest *request;//要使用可变的请求对象
    @property(nonatomic,strong)NSURLConnection *conn;

    @end
    @implementation ViewController

    - (void)viewDidLoad {
        [super viewDidLoad];
        self.cachePath=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)firstObject];
     
    }
    - (IBAction)downloadBigFile:(UIButton *)sender {
        NSURL *url=[NSURL URLWithString:@"http://localhost:80/Evernote.zip"];
     
        self.totalLength=0;
        self.currentLength=0;
        self.request=[NSMutableURLRequest requestWithURL:url];
        //设置range:bytes=0-
        NSString *range= [NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
        [self.request setValue:range forHTTPHeaderField:@"Range"];
        self.conn = [NSURLConnection connectionWithRequest:self.request delegate:self];
    }
    - (IBAction)cancelDownLoad:(UIButton *)sender {
        //取消下载
        [self.conn cancel];
        self.conn=nil;
    }
    - (IBAction)resumeDownLoad:(UIButton *)sender {
        //恢复下载
        //Range:bytes=
        NSString *range=[NSString stringWithFormat:@"bytes=%lld-",self.currentLength];
        [self.request setValue:range forHTTPHeaderField:@"Range"];
        self.conn = [NSURLConnection connectionWithRequest:self.request delegate:self];
    }
    //客户端请求成功,接收到响应response
    -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    //获取返回的代号,判断出服务器响应的结果
        NSInteger status=[(NSHTTPURLResponse *)response statusCode];
        NSLog(@"status:%ld",(long)status);
        if (status == 206) {
            //在沙盒Caches/文件夹下,创建出用来存储数据的文件
            NSFileManager *manage=[NSFileManager defaultManager];
            NSString *fliePath=[self.cachePath stringByAppendingPathComponent:@"text.zip"];
            NSLog(@"写入的文件路径:%@",fliePath);
            [manage createFileAtPath:fliePath contents:nil attributes:nil];
            //获取文件的总大小(为了显示进度)
            self.writeHandle=[NSFileHandle fileHandleForWritingAtPath:fliePath];
            if (self.currentLength ==0) {//服务器返回文件的剩余大小,因此要获取一次返回的大小
                self.totalLength=response.expectedContentLength;
            } 
            NSLog(@"文件的总大小:%lld",self.totalLength); 
        }
    }
    //接收到数据
    -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
        //当前接收数据包的大小
        static int i=0;
        i++;
        NSLog(@"当前接收数据大小_%d:%ld",i,(unsigned long)data.length);
        //移动到文件尾部
        [self.writeHandle seekToEndOfFile];
       //写入文件
        [self.writeHandle writeData:data];
        self.currentLength +=data.length;
        NSLog(@"总接收数据:%lld",self.currentLength);
        self.progressView.progress = (double)self.currentLength / self.totalLength;
        NSLog(@"当前进度:%f",self.progressView.progress);
    }
    //下载完成后,关闭句柄
    -(void)connectionDidFinishLoading:(NSURLConnection *)connection{
        [self.writeHandle closeFile];
    }
    //错误处理
    -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
        NSLog(@"error : %@",[error userInfo])
    }
     
    //*********************************************
    苹果公司在iOS7,给SDK中添加了新的网络处理类:NSURLSession
    它与URLConnection是并列关系.
    URLSession包含了URLConnection的所有功能, 额外还添加了以下4点特性:
    1.通过URL将数据下载到内存
    2.通过URL将数据下载到文件系统
    3.将数据上传到指定的URL
    4.在后台完成上述的操作
    适用场景:     ios7+; 封装很多实现细节;
    使用NSURLSession之前
    选择工作模式:
    session(会话)三个类型:
    session1  <- defaultSessionConfiguration:(默认模式),类似于原来的NSURLConnection,使用的是基于磁盘缓存的持久化策略,使用用户keychain中保存的证书进行认证授权
    session2  <- ephemeralSessionConfiguration:(瞬时模式),不会在磁盘中保存任何数据,所有与会话有关的caches、证书、cookies等都保存在RAM中,因此当程序会话无效时,这些缓存数据就会被自动清理。
    session3  <- backgroundSessionConfiguration:(后台模式),在后天完成上传和下载,在创建congfiguration对象的时候需要提供一个NSString类型的ID用来标示完成工作的后台会话。

    task三个类型:
    1、NSURLSessionDataTask:
         处理小数据相关的任务(不包括下载和上传)
         例子: 返回json数据; 返回html文件(放在UIWebView);
                   返回xml数据
    2、NSURLSessionDownloadTask:
    //采用的是子线程下载
         主要用于下载任务; delegate方法接收或者处理服务器返回的数据
    3、NSURLSessionUploadTask:
         主要用于上传任务;
    后台运行:
    主要configuration的配置: backgroundSessionConfiguration
    获得NSURLSession对象:
    第一种方式是使用静态的sharedSession方法,该类使用共享的会话,该会话使用全局的Cache,Cookie和证书。
    第二种方式是通过sessionWithConfiguration:方法创建对象,也就是创建对应配置的会话,与NSURLSessionConfiguration合作使用。
    第三种方式是通过sessionWithConfiguration:delegate:delegateQueue方法创建对象,二三两种方式可以创建一个新会话并定制其会话类型。该方式中指定了session的委托和委托所处的队列。当不再需要连接时,可以调用Session的invalidateAndCancel直接关闭,或者调用finishTasksAndInvalidate等待当前Task结束后关闭。这时Delegate会收到URLSession:didBecomeInvalidWithError:这个事件。Delegate收到这个事件之后会被解引用。
     
    //---------------------------------使用步骤--------------------------------------------------------
    1、准备网络资源地址URL、发送请求NSURLRequest
    2、创建NSURLSession对象
    3、执行下载任务NSURLSessionDownloadTask
    4、下载完成后,对文件的处理
    NSURLSessionDownloadTask  *downloadTask=[session downloadTaskWithRequest:request
                        completionHandler:^(NSURL *location,//location是位于沙盒中的tmp目录下,要转移(会被定时清理的) 
                        NSURLResponse *response,//服务器的响应
                        NSError *error){
              });
    //------------------------------------------------------------------------------------------------
    //————————————————-----------—————简单的使用方式-------------------------------------------
     
    - (IBAction)downLoad:(UIButton *)sender {
        //1创建NSURLSession对象
        NSURLSession *session=[NSURLSession sharedSession];//使用默认的session(回话)方式
        NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=298400068,822827541&fm=116&gp=0.jpg"]];
        NSURLSessionDownloadTask  *downloadTask=[session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
            NSLog(@"下载完成:%@",[NSThread currentThread]);//子线程
           
            NSInteger status=[(NSHTTPURLResponse *)response statusCode];//服务器返回的编号
            NSLog(@"status:%ld",(long)status);
            if (status ==200) {
                NSLog(@"location:%@",location);
    //location是位于沙盒中的tmp目录下,要转移(会被定时清理的)
    //要将文件转移到Caches中
                //1、获取路径
                NSLog(@"response : %@",response);
                NSString *path=[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)firstObject]stringByAppendingPathComponent:@"mm.jpg"];
                NSLog(@"path :%@",path);
                //2、移动文件
                [[NSFileManager defaultManager]moveItemAtPath:location.path toPath:path error:nil];
                //显示图片
                UIImage *image=[UIImage imageNamed:path];
    //4.回到主线程将图片显示在界面上,为什么要回到主线程?答:因为视图层都在主线程中
                dispatch_async(dispatch_get_main_queue(), ^{
                    self.imageView.image=image;
                });
            }
        }];
        //执行下载任务
        [downloadTask resume];
    }
    //------------------------------------------------------------------------------------------------
    //------------------------------------------------------------------------------------------------
    //------------------------------------------------------------------------------------------------
  • 相关阅读:
    java Des 加密解密技术
    JAVA处理外部链接的方法
    javascript 中escape、encodeURI、encodeURIComponent 区别
    JQuery与JS 遍历和操作 父页面控件的比较
    JS 添加删除元素 /DOM
    jquery 验证所有text,textare非法字符
    jquery url检测遇到的jquery跨域问题及JSONP的使用
    二叉树遍历非递归算法——后序遍历
    二叉树遍历非递归算法——中序遍历
    二叉树遍历非递归算法——先序遍历
  • 原文地址:https://www.cnblogs.com/lignpeng/p/5458401.html
Copyright © 2011-2022 走看看