iOS中的网络编程-NSURLConnection(二)

HTTP请求的方案

  • NSURLConnection:用法简单,(坑比较多)
  • NSURLSession:功能比NSURLConnection强大,苹果目前比较推荐
  • CFNetwork :苹果底层,纯C语言
  • ASIHTTPRequest:功能强大,已停止更新
  • AFNetworking:简单易用,三方库中比较主流
NSURLConnection
  • 基本类
    • NSURL:请求地址
    • NSURLRequest:代表一个请求,它包含(NSURL对象、请求方法、请求头、请求体、请求超时时间…)
    • NSMutableURLRequest:是NSURLRequest子类,可修改Request里的信息
    • NSURLConnection:负责发送请求,建立客户端和服务器的连接,发送数据并收集来自服务器响应的数据
    • 接收大数据一般使用代理方法,小数据使用块方法即可
  • 使用步骤

    • 创建一个NSURL对象,设置请求路径
    • 传入NSURL创建一个NSURLRequest对象,设置请求头和请求体
    • 使用NSURLConnection发送请求
      这里写图片描述
  • 请求方式

    • 同步请求(当前线程)
    • 异步请求(开启新线程)
  • 同步Get请求

- (IBAction)syncGet:(id)sender {
    NSURL *url = [NSURL URLWithString:@"http://localhost:3000/ping"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLResponse *response = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
    NSString *requestInfo  = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    self.textView.text = requestInfo;
    NSLog(@"syncGetData:%@--%@",requestInfo,[NSThread currentThread]);

}
  • 同步Post请求
- (IBAction)syncPost:(id)sender {
    NSURL *url = [NSURL URLWithString:@"http://localhost:3000/upload"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    //更改请求方法
    request.HTTPMethod = @"POST";
    //设置超时5s
    request.timeoutInterval = 5;
    request.HTTPBody = [@"ss" dataUsingEncoding:NSUTF8StringEncoding];
    NSURLResponse *response = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
    NSString *requestInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"syncPostData:%@--%@",requestInfo,[NSThread currentThread]);
}
  • 异步Get请求
- (IBAction)asynGet:(id)sender {
    NSURL *url = [NSURL URLWithString:@"http://localhost:3000/ping"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    //queue:可以设置指定的线程,如主线程[NSOperationQueue mainQueue]
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse * response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        NSString *requestInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"asynGetData:%@--%@",requestInfo,[NSThread currentThread]);
    }];
}
  • 异步Post请求
NSURL *url = [NSURL URLWithString:@"http://localhost:3000/upload"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    //更改请求方法
    request.HTTPMethod = @"POST";
    //设置超时5s
    request.timeoutInterval = 5;
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {        
        NSString *requestInfo = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"asynPostData:%@--%@",requestInfo,[NSThread currentThread]);
    }];
  • 小文件下载
NSURL *url = [NSURL URLWithString:@"http://localhost:3000/download"];

    //方式一:data直接下载
    NSData *data = [NSData dataWithContentsOfURL:url];
    NSLog(@"\n NSData---%lu",(unsigned long)data.length);
    self.textView.text = [NSString stringWithFormat:@"下载完成:%lu",(unsigned long)data.length];


    //方式二:通过请求下载
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        NSLog(@"\n NSURLConnection---%lu",(unsigned long)data.length);
        self.textView.text = [NSString stringWithFormat:@"下载完成:%lu",(unsigned long)data.length];

    }];
  • 大文件下载

    • 一般下载方式
      1、收到服务器响应后初始化一个要存放data的临时缓存区
      2、将不断接收的data存放临时缓存区里
      3、接收完毕后将临时缓存里的data放入本地存储文件
      4、存储完毕后,将临时缓存区清空
      弊端:正整个下载过程中,app内存会不断增长,直到将数据写入才会降下来才会降下来
    NSURL *url = [NSURL URLWithString:@"http://localhost:3000/download"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [NSURLConnection connectionWithRequest:request delegate:self];
    
    ---------
    
        -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response{
            //获取文件总长度
            self.contentLength = [response.allHeaderFields[@"Content-Length"] integerValue];
            self.fileData = [NSMutableData data];
        }
    
        -(void)connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data{
               [self.fileData appendData:data];
               NSLog(@"下载进度--%.2f%%",(1.0 * self.fileData.length / self.contentLength) * 100);
                self.textView.text = [NSString stringWithFormat:@"下载进度--%.2f%%",(1.0 * self.fileData.length / self.contentLength) * 100];
        }
    
    -(void)connectionDidFinishLoading:(NSURLConnection *)connection{
            //将临时缓存去的data写入本地文件
        [self.fileData writeToFile:SaveFile atomically:YES];
        self.fileData = nil;
        NSLog(@"写入完毕--%@",SaveFile);
        self.textView.text = [NSString stringWithFormat:@"%@ \n写入完毕--%@",self.textView.text,SaveFile];
    }
    • 优化下载过程
      为了避免app内存不断增长,最好处理方法是边下载边存储
      1、收到服务器响应后,创建一个本地存储的空文件
      2、将不断接收的data存放临时缓存区里
      3、接收完毕后将临时缓存里的data放入本地存储
      4、存储完毕后,将临时缓存区清空

      NSURL *url = [NSURL URLWithString:@"http://localhost:3000/download"];
      NSURLRequest *request = [NSURLRequest requestWithURL:url];
      [NSURLConnection connectionWithRequest:request delegate:self];
      
      ---------
          -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response{
              //获取文件总长度
              self.contentLength = [response.allHeaderFields[@"Content-Length"] integerValue];
              //新建一个空文件
              [[NSFileManager defaultManager]createFileAtPath:SaveFile contents:nil attributes:nil];
              //接收得到data,直接把data写入创建好的文件
              self.handle = [NSFileHandle fileHandleForWritingAtPath:SaveFile];
           }
      
          -(void)connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data{
      
              //指定每一次data写入位置(是指针指向目前存储数据的最后面,避免上一次收到的data覆盖目前的data)
              [self.handle seekToEndOfFile];
              //写入数据
              [self.handle writeData:data];
              self.currentLength += data.length;
              NSLog(@"下载进度--%.2f%%",(1.0 * self.currentLength / self.contentLength) * 100);
              self.textView.text = [NSString stringWithFormat:@"下载进度--%.2f%%",(1.0 * self.currentLength / self.contentLength) * 100]; 
              }
      
      -(void)connectionDidFinishLoading:(NSURLConnection *)connection{
           //存储完毕
          //关闭handle
          [self.handle closeFile];
          self.textView.text = [NSString stringWithFormat:@"%@ \n写入完毕--%@",self.textView.text,SaveFile];
      }   
    • 通过stream下载
      以数据流的形式进行存储

    NSURL *url = [NSURL URLWithString:@"http://localhost:3000/download"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    
    [NSURLConnection connectionWithRequest:request delegate:self];
    ------
    
    -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response{
            //利用NSOutputStream往path中写data(append为YES,每次写入都是追加到文件尾部)
            self.stream = [[NSOutputStream alloc]initToFileAtPath:SaveFile append:YES];
        //
            [self.stream open];
    }
    
    -(void)connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data{
    [self.stream write:[data bytes] maxLength:data.length];
    }
    
    -(void)connectionDidFinishLoading:(NSURLConnection *)connection{
        //关闭stream
        [self.stream close];
        NSLog(@"写入完毕--%@",SaveFile);
        self.textView.text = [NSString stringWithFormat:@"%@ \n写入完毕--%@",self.textView.text,SaveFile];
    }
    
  • 创建压缩文件
    pod SSZipArchive库

NSArray *paths = @[
                   @"/Users/soso/Desktop/OTP2.png",
                   @"/Users/soso/Desktop/OTP1.png"
                   ];
    [SSZipArchive createZipFileAtPath:@"/Users/soso/Desktop/test.zip" withFilesAtPaths:paths];
}
  • 解压文件
     [SSZipArchive unzipFileAtPath:@"/Users/soso/Desktop/test.zip" toDestination:@"/Users/soso/Desktop"];
  • NSURLConnection与Runloop的关系
    虽然发送请求写在主线程里,其实内部在是子线程进行的,但是所以的回调方法都是在主线程返回,如果想让回调方法在子线程中进行,那么通过设置队列的方式去其代理回调在其子线程执行
NSURL *url = [NSURL URLWithString:@"http://localhost:3000/download"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLConnection *connection =  [NSURLConnection connectionWithRequest:request delegate:self];    

//决定代理方法在哪个队列执行
[connection setDelegateQueue:[[NSOperationQueue alloc]init]];


-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response{
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data{

}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection{

}

如果将其请求放在子线程中调用,会导致一个问题,代理的回调方法将无响应,其内部应该当请求发出去时,代理方法将等待服务器的回调,内部应该有一个runloop一直在监听代理回调,一旦runloop监听到source,就去执行处理,为什么在子线程调用就不好使,是因为子线程中runloop默认是没有启动的,因此需要手动启动runloop

dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSURL *url = [NSURL URLWithString:@"http://localhost:3000/download"];
        NSURLRequest *request = [NSURLRequest requestWithURL:url];
        [NSURLConnection connectionWithRequest:request delegate:self];

        //启动子线程runloop
        [[NSRunLoop currentRunLoop] run];

});

猜你喜欢

转载自blog.csdn.net/hejiasu/article/details/80748029