NSURLSession - NSURLSessionTask 和 delegate

来源:互联网 发布:淘宝宝贝涨价被降权了 编辑:程序博客网 时间:2024/06/15 12:29

转:http://blog.csdn.net/hello_hwc/article/details/44565115

前言: 
这是IOS 网络开发系列的第三篇文章,这篇文章主要介绍了NSURLSession以及NSURLSessionTask这个抽象类,和NSURLSessionDataTask的使用和代理方法。 
本篇的顺序, 

1. demo效果 
2. NSURLSessionTask属性方法介绍  
3. NSURLSessionDataTask的使用和代理方法  
4. Demo的源码讲解


一 Demo效果

暂停-继续 
 
取消 


三 NSURLSessionTask

Task是由Session创建的,Session会保持对Task的一个强引用,直到Task完成或者出错才会释放。通过NSURLSessionTask可以获得Task的各种状态,以及对Task进行取消,挂起,继续等操作。一共包括三种Task,三种Task的结构如图。本文主要讲解的是DataTask。 

管理task的状态的方法

- (void)cancel //取消一个task- (void)resume //如果task在挂起状态,则继续执行task- (void)suspend //挂起task
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

获得task的执行情况的属性

countOfBytesExpectedToReceive countOfBytesReceivedcountOfBytesExpectedToSendcountOfBytesSent
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

task的综合信息

currentRequest // 当前活跃的requestoriginalRequest // 在task创建的时候传入的request(有可能会重定向)response // 服务器对当前活跃请求的响应taskDescription // 描述当前tasktaskIdentifier // 用来区分Task的描述符error //Task失败的错误信息
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

task状态的枚举

typedef NS_ENUM (NSInteger,   NSURLSessionTaskState ) {   NSURLSessionTaskStateRunning = 0,   NSURLSessionTaskStateSuspended = 1,   NSURLSessionTaskStateCanceling = 2,   NSURLSessionTaskStateCompleted = 3,};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

四 NSURLSessionDataTask代理

DataTask是用来干嘛的呢? 
用来下载数据到内存里,数据的格式是NSData 
dataTask使用的过程中,有两种方式来处理结果

第一种,通过block的方式(不关注过程,只关注结果,使用简单)

举个例子 
下载一幅图片,完成后显示到ImageView。下面代码看起来很简单吧。

NSURLSessionDataTask * task = [self.session dataTaskWithURL:[NSURL URLWithString:imageURL] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {        if (!error) {            UIImage * image = [UIImage imageWithData:data];            self.imageview.image = image;        }    }];    [task resume];
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

第二种通过代理方法来管理session和task。( 可以获得全部过程,但是较为复杂)

主要使用到三种代理中的事件 
NSURLSessionDelegate用来处理Session层次的事件

Session被 invalide得到的事件- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error
  • 1
  • 2
  • 1
  • 2

Session层次收到了授权,证书等问题

- (void)URLSession:(NSURLSession *)sessiondidReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,                             NSURLCredential *credential))completionHandler
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

NSURLSessionTaskDelegate是使用代理的时候,任何种类task都要实现的代理 
Task完成的事件

- (void)URLSession:(NSURLSession *)session              task:(NSURLSessionTask *)taskdidCompleteWithError:(NSError *)error
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

Task层次收到了授权,证书等问题

- (void)URLSession:(NSURLSession *)session              task:(NSURLSessionTask *)taskdidReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,                             NSURLCredential *credential))completionHandler
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

将会进行HTTP,重定向

- (void)URLSession:(NSURLSession *)session              task:(NSURLSessionTask *)taskwillPerformHTTPRedirection:(NSHTTPURLResponse *)response        newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest *))completionHandler
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

NSURLSessionDataDelegate特别用来处理dataTask的事件 
收到了Response,这个Response包括了HTTP的header(数据长度,类型等信息),这里可以决定DataTask以何种方式继续(继续,取消,转变为Download)

- (void)URLSession:(NSURLSession *)session          dataTask:(NSURLSessionDataTask *)dataTaskdidReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

DataTask已经转变成DownloadTask

- (void)URLSession:(NSURLSession *)session          dataTask:(NSURLSessionDataTask *)dataTaskdidBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

每收到一次Data时候调用

- (void)URLSession:(NSURLSession *)session          dataTask:(NSURLSessionDataTask *)dataTask    didReceiveData:(NSData *)data
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

是否把Response存储到Cache中

- (void)URLSession:(NSURLSession *)session          dataTask:(NSURLSessionDataTask *)dataTask willCacheResponse:(NSCachedURLResponse *)proposedResponse completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

五 Demo源码讲解

#import "ViewController.h"@interface ViewController ()<NSURLSessionDelegate,NSURLSessionTaskDelegate,NSURLSessionDataDelegate>@property (strong,nonatomic)UIImageView * imageview;@property (strong,nonatomic)NSURLSession * session;@property (strong,nonatomic)NSURLSessionDataTask * dataTask;@property (weak, nonatomic) IBOutlet UIProgressView *progressview;@property (nonatomic)NSUInteger expectlength;@property (strong,nonatomic) NSMutableData * buffer;@endstatic NSString * imageURL = @"http://f12.topit.me/o129/10129120625790e866.jpg";@implementation ViewController//属性全部采用惰性初始化#pragma mark - lazy property-(UIImageView *)imageview{    if (!_imageview) {        _imageview = [[UIImageView alloc] initWithFrame:CGRectMake(40,40,300,200)];        _imageview.backgroundColor = [UIColor lightGrayColor];        _imageview.contentMode = UIViewContentModeScaleToFill;    }    return _imageview;}-(NSMutableData *)buffer{    if (!_buffer) {        _buffer = [[NSMutableData alloc] init];    }    return _buffer;}-(NSURLSession*)session{    if (!_session) {        NSURLSessionConfiguration * configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];        _session = [NSURLSession sessionWithConfiguration:configuration                                                 delegate:self                                            delegateQueue:[NSOperationQueue mainQueue]];    }    return _session;}-(NSURLSessionDataTask *)dataTask{    if (!_dataTask) {        _dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:imageURL]];    }    return _dataTask;}#pragma mark - life circle of viewcontroller- (void)viewDidLoad {    [super viewDidLoad];    [self.view addSubview:self.imageview];    [self.dataTask resume];//Task要resume彩绘进行实际的数据传输    [self.session finishTasksAndInvalidate];//完成task就invalidate}#pragma mark - target-action//注意判断当前Task的状态- (IBAction)pause:(UIButton *)sender {    if (self.dataTask.state == NSURLSessionTaskStateRunning) {        [self.dataTask suspend];    }}- (IBAction)cancel:(id)sender {    switch (self.dataTask.state) {        case NSURLSessionTaskStateRunning:        case NSURLSessionTaskStateSuspended:            [self.dataTask cancel];            break;        default:            break;    }}- (IBAction)resume:(id)sender {    if (self.dataTask.state == NSURLSessionTaskStateSuspended) {        [self.dataTask resume];    }}#pragma mark -  URLSession delegate method-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{    NSUInteger length = [response expectedContentLength];    if (length != -1) {        self.expectlength = [response expectedContentLength];//存储一共要传输的数据长度        completionHandler(NSURLSessionResponseAllow);//继续数据传输    }else{        completionHandler(NSURLSessionResponseCancel);//如果Response里不包括数据长度的信息,就取消数据传输        UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"error"                                                         message:@"Do not contain property of expectedlength"                                                        delegate:nil                                               cancelButtonTitle:@"OK"                                               otherButtonTitles:nil];        [alert show];    }}-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{    [self.buffer appendData:data];//数据放到缓冲区里    self.progressview.progress = [self.buffer length]/((float) self.expectlength);//更改progressview的progress}-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{    if (!error) {        dispatch_async(dispatch_get_main_queue(), ^{//用GCD的方式,保证在主线程上更新UI            UIImage * image = [UIImage imageWithData:self.buffer];            self.imageview.image = image;            self.progressview.hidden = YES;            self.session = nil;            self.dataTask = nil;        });    }else{        NSDictionary * userinfo = [error userInfo];        NSString * failurl = [userinfo objectForKey:NSURLErrorFailingURLStringErrorKey];        NSString * localDescription = [userinfo objectForKey:NSLocalizedDescriptionKey];        if ([failurl isEqualToString:imageURL] && [localDescription isEqualToString:@"cancelled"]) {//如果是task被取消了,就弹出提示框            UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Message"                                                             message:@"The task is canceled"                                                            delegate:nil                                                   cancelButtonTitle:@"OK"                                                   otherButtonTitles:nil];            [alert show];        }else{            UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Unknown type error"//其他错误,则弹出错误描述                                                             message:error.localizedDescription                                                            delegate:nil                                                   cancelButtonTitle:@"OK"                                                   otherButtonTitles:nil];            [alert show];        }        self.progressview.hidden = YES;        self.session = nil;        self.dataTask = nil;    }}@end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
0 0
原创粉丝点击