• 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 }
  • 相关阅读:
    JS 页面生成锚点
    JavaScript AMD模块化规范
    Canvas文字的渲染基础 Better
    Canvas曲线绘制 Better
    clickhouse配置登录密码
    git pull 拉取报错:fatal: refusing to merge unrelated histories
    JAVA根据A星算法规划起点到终点二维坐标的最短路径
    JAVA使用netty建立websocket连接
    CSS设置文字超出部分自动换行
    SpringBoot(SpringMVC)使用addViewControllers设置统一请求URL重定向(映射、转发)配置
  • 原文地址:https://www.cnblogs.com/liufeng24/p/3504393.html
Copyright © 2020-2023  润新知