zoukankan      html  css  js  c++  java
  • ios开发之网络数据的下载与上传

    要实现网络数据的下载与上传,主要有三种方式

    > NSURLConnection  针对少量数据,使用“GET”或“POST”方法从服务器获取数据,使用“POST”方法向服务器传输数据;

    > NSURLSession(ios7.0新推出的) 针对大量数据,可使用“GET”方法实现线程安全的多线程下载,监控下载进度等,也可以使用“PUT”方法实现上传[put 方法存在严重的安全隐患,目前很少有服务器支持此种上传方式];

    > AFNetWorking(2.0之前的版本) 对NSURLConnection进行封装的第三方开源框架,实现了大量数据的下载与上传,但是对于线程安全没有较好的控制措施;


    推荐用法:对于少量数据(例如平时的网页信息)的下载与上传,直接使用NSURLConnection,对于大量数据的下载使用NSURLSession,对于大量数据的上传使用AFNetWorking

    NSURLConnection:

      1> GET

    // 1. 定义URL,确定要访问的地址
    NSURL *url = [NSURL URLWithString:urlString];
    // 2. 定义URLRequest,确定网络访问请求,在GET方法中直接用URL即可
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:2.0f];
    
    //===================================================
    NSURLResponse *response = nil;
    NSError *error = nil;
    // 同步请求的应用场景:例如:网银账户的登录!
    // 一定要获取到某个网络返回数据后,才能进行下一步操作的场景!
    
    // 发送同步请求,respone&error要带地址的原因就是为了方法执行后,能够方便使用response&error
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    //-------------------------------------------------
    // 发送异步请求[有同步则不需要异步,反之亦然]
    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        // 块代码的内容会在网络访问后执行
        // 块代码是预先定义好的代码片段,在满足某个条件时执行的。
        NSLog(@"%@", [NSThread currentThread]);
    }];

      2> POST

    // 1. 定义URL,确定要访问的地址
    NSURL *url = [NSURL URLWithString:urlString];
    // 2. 定义请求,生成数据体添加到请求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 1) 指定网络请求的方法
    request.HTTPMethod = @"POST";
    
    // 2) 生成数据体
    // * 先生成字符串
    NSString *bodyStr = [NSString stringWithFormat:@"username=%@&password=%@", userName, password];
    // * 将字符串转换成NSData
    request.HTTPBody = [bodyStr dataUsingEncoding:NSUTF8StringEncoding];
    
    // 提示:POST请求多用于用户登录,或者上传文件,在实际开发中,“POST请求的参数及地址”需要与公司的后端程序员沟通。
    // POST同样具备同步和异步方法,与get中同步异步方法相同

    NSURLSession

     1     // url
     2     NSURL *url = [NSURL URLWithString:strURL];
     3     
     4     // request
     5     NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3.0f];
     6     
     7     // session
     8     NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
     9     
    10     _downloadTask = [session downloadTaskWithRequest:request];// NSURLSessionDownloadTask *_downloadTask; 成员变量
    11     
    12     [_downloadTask resume];

    苹果官方提供的Session还是非常给力的,使用也很方便。 让当前控制器成为当前session的代理,并且实现其中的代理方法,便可以对整个下载过程了如指掌

     1 #pragma mark - download代理方法
     2 
     3 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
     4 {
     5     NSLog(@"error- %@", error.localizedDescription);
     6 }
     7 
     8 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
     9 {
    10     CGFloat percent = (CGFloat)totalBytesWritten / totalBytesExpectedToWrite;
    11 
    12     dispatch_async(dispatch_get_main_queue(), ^{
    13         
    14         _progress.progress = percent; // 进度
    15         _progressLabel.text = [NSString stringWithFormat:@"当前:%.1fKb/s,进度:%.2f%%", bytesWritten / 1024.0f, percent * 100];
    16     });
    17 }
    18 
    19 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
    20 {
    21     NSLog(@"%@", location);
    22 }
    23 
    24 - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
    25 {
    26     NSLog(@"%lld", fileOffset);
    27 }

    AFNetWorking

    下载使用示例代码:

     1 #pragma mark 下载
     2 - (IBAction)download
     3 {
     4     // 1. 建立请求  _httpClient 是AFHTTPClient实例化出来的成员变量
     5     NSURLRequest *request = [_httpClient requestWithMethod:@"GET" path:@"download/Objective-C2.0.zip" parameters:nil];
     6     
     7     // 2. 操作
     8     AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
     9     
    10     _downloadOperation = op;
    11     
    12     // 下载
    13     // 指定文件保存路径,将文件保存在沙盒中
    14     NSArray *docs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    15     NSString *path = [docs[0] stringByAppendingPathComponent:@"download.zip"];
    16     
    17     op.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
    18     
    19     // 设置下载进程块代码
    20     /*
    21      bytesRead                      当前一次读取的字节数(100k)
    22      totalBytesRead                 已经下载的字节数(4.9M)
    23      totalBytesExpectedToRead       文件总大小(5M)
    24      */
    25     [op setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
    26         
    27         // 设置进度条的百分比
    28         CGFloat precent = (CGFloat)totalBytesRead / totalBytesExpectedToRead;
    29         NSLog(@"%f", precent);
    30         
    31         _progressView.progress = precent;
    32     }];
    33     
    34     // 设置下载完成操作
    35     [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    36         
    37         // 下载完成之后,解压缩文件
    38         /*
    39          参数1:要解结压缩的文件名及路径 path - > download.zip
    40          参数2:要解压缩到的位置,目录    - > document目录
    41          */
    42         [SSZipArchive unzipFileAtPath:path toDestination:docs[0]];
    43         
    44         // 解压缩之后,将原始的压缩包删除
    45         // NSFileManager专门用于文件管理操作,可以删除,复制,移动文件等操作
    46         // 也可以检查文件是否存在
    47         [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
    48         
    49         // 下一步可以进行进一步处理,或者发送通知给用户。
    50         NSLog(@"下载成功");
    51     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    52         NSLog(@"下载失败");
    53     }];
    54     
    55     // 启动下载
    56     [_httpClient.operationQueue addOperation:op];
    57  }

    上传示例代码

     1 #pragma mark - 文件上传
     2 - (IBAction)uploadImage
     3 {
     4     /*
     5      此段代码如果需要修改,可以调整的位置
     6      
     7      1. 把upload.php改成网站开发人员告知的地址
     8      2. 把file改成网站开发人员告知的字段名
     9      */
    10     // 1. httpClient->url
    11     
    12     // 2. 上传请求POST
    13     NSURLRequest *request = [_httpClient multipartFormRequestWithMethod:@"POST" path:@"upload.php" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
    14         // 在此位置生成一个要上传的数据体
    15         // form对应的是html文件中的表单
    16         /*
    17          参数
    18          1. 要上传的[二进制数据]
    19          2. 对应网站上[upload.php中]处理文件的[字段"file"]
    20          3. 要保存在服务器上的[文件名]
    21          4. 上传文件的[mimeType]
    22          */
    23         UIImage *image = [UIImage imageNamed:@"头像1"];
    24         NSData *data = UIImagePNGRepresentation(image);
    25         
    26         // 在网络开发中,上传文件时,是文件不允许被覆盖,文件重名
    27         // 要解决此问题,
    28         // 可以在上传时使用当前的系统事件作为文件名
    29         NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    30         // 设置时间格式
    31         formatter.dateFormat = @"yyyyMMddHHmmss";
    32         NSString *str = [formatter stringFromDate:[NSDate date]];
    33         NSString *fileName = [NSString stringWithFormat:@"%@.png", str];
    34         
    35         [formData appendPartWithFileData:data name:@"file" fileName:fileName mimeType:@"image/png"];
    36     }];
    37     
    38     // 3. operation包装的urlconnetion
    39     AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    40     
    41     [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    42         NSLog(@"上传完成");
    43     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    44         NSLog(@"上传失败->%@", error);
    45     }];
    46     
    47     [_httpClient.operationQueue addOperation:op];
    48 }

    注意:AFN中数据不是线程安全的,如果使用暂停、继续功能会造成数据混乱,所以在使用AFN时,尽量不要暂停下载或者上传

     AFN还可以用来判断网络状态

     1 - (IBAction)checkNetwork:(id)sender
     2 {
     3     // 1. AFNetwork 是根据是否能够连接到baseUrl来判断网络连接状态的
     4     // 提示:最好使用门户网站来判断网络连接状态。
     5     NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
     6     
     7     AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:url];
     8     _httpClient = client;
     9     
    10     [_httpClient setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
    11 
    12         // 之所以区分无线和3G主要是为了替用户省钱,省流量
    13         // 如果应用程序占流量很大,一定要提示用户,或者提供专门的设置,仅在无线网络时使用!
    14         switch (status) {
    15             case AFNetworkReachabilityStatusReachableViaWiFi:
    16                 NSLog(@"无线网络");
    17                 break;
    18             case AFNetworkReachabilityStatusReachableViaWWAN:
    19                 NSLog(@"3G网络");
    20                 break;
    21             case AFNetworkReachabilityStatusNotReachable:
    22                 NSLog(@"未连接");
    23                 break;
    24             case AFNetworkReachabilityStatusUnknown:
    25                 NSLog(@"未知错误");
    26                 break;
    27         }
    28     }];
    29 }
  • 相关阅读:
    Linux内核RPC请求过程
    二分图
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 文本加密
    Java蓝桥杯 算法提高 九宫格
    Java蓝桥杯 算法提高 九宫格
  • 原文地址:https://www.cnblogs.com/liufeng24/p/3504393.html
Copyright © 2011-2022 走看看