AF ios开发之网络数据的下载与上传


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 }
复制代码

你可能感兴趣的:(ios)