iOS網(wǎng)絡開發(fā)NSURLSession

NSURLSessionTask

Task是由Session創(chuàng)建的,Session會保持對Task的一個強引用,直到Task完成或者出錯才會釋放。通過NSURLSessionTask可以獲得Task的各種狀態(tài),以及對Task進行取消,掛起,繼續(xù)等操作。一共包括三種Task,三種Task的結(jié)構(gòu)如圖。本文主要講解的是DataTask。


管理task的狀態(tài)的方法
- (void)cancel //取消一個task
- (void)resume //如果task在掛起狀態(tài),則繼續(xù)執(zhí)行task
- (void)suspend //掛起task
獲得task的執(zhí)行情況的屬性
countOfBytesExpectedToReceive 
countOfBytesReceived
countOfBytesExpectedToSend
countOfBytesSent
task的綜合信息
currentRequest // 當前活躍的request
originalRequest // 在task創(chuàng)建的時候傳入的request(有可能會重定向)
response // 服務器對當前活躍請求的響應
taskDescription // 描述當前task
taskIdentifier // 用來區(qū)分Task的描述符
error //Task失敗的錯誤信息
task狀態(tài)的枚舉
typedef NS_ENUM (NSInteger,
   NSURLSessionTaskState ) {
   NSURLSessionTaskStateRunning = 0,
   NSURLSessionTaskStateSuspended = 1,
   NSURLSessionTaskStateCanceling = 2,
   NSURLSessionTaskStateCompleted = 3,
};

NSURLSessionDataTask代理

DataTask是用來干嘛的呢?
用來下載數(shù)據(jù)到內(nèi)存里,數(shù)據(jù)的格式是NSData
dataTask使用的過程中,有兩種方式來處理結(jié)果

第一種,通過block的方式(不關注過程,只關注結(jié)果,使用簡單)

舉個例子
下載一幅圖片,完成后顯示到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];
第二種通過代理方法來管理session和task。( 可以獲得全部過程,但是較為復雜)

主要使用到三種代理中的事件
NSURLSessionDelegate用來處理Session層次的事件

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

Session層次收到了授權(quán),證書等問題

- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
                             NSURLCredential *credential))completionHandler

NSURLSessionTaskDelegate是使用代理的時候,任何種類task都要實現(xiàn)的代理
Task完成的事件

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error

Task層次收到了授權(quán),證書等問題

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition,
                             NSURLCredential *credential))completionHandler

將會進行HTTP,重定向

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest *))completionHandler

NSURLSessionDataDelegate特別用來處理dataTask的事件
收到了Response,這個Response包括了HTTP的header(數(shù)據(jù)長度,類型等信息),這里可以決定DataTask以何種方式繼續(xù)(繼續(xù),取消,轉(zhuǎn)變?yōu)镈ownload)

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler

DataTask已經(jīng)轉(zhuǎn)變成DownloadTask

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask

每收到一次Data時候調(diào)用

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data

是否把Response存儲到Cache中

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
 willCacheResponse:(NSCachedURLResponse *)proposedResponse
 completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler

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;
@end

static 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彩繪進行實際的數(shù)據(jù)傳輸
    [self.session finishTasksAndInvalidate];//完成task就invalidate
}
#pragma mark - target-action
//注意判斷當前Task的狀態(tài)
- (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];//存儲一共要傳輸?shù)臄?shù)據(jù)長度
        completionHandler(NSURLSessionResponseAllow);//繼續(xù)數(shù)據(jù)傳輸
    }else{
        completionHandler(NSURLSessionResponseCancel);//如果Response里不包括數(shù)據(jù)長度的信息,就取消數(shù)據(jù)傳輸
        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];//數(shù)據(jù)放到緩沖區(qū)里
    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"http://其他錯誤,則彈出錯誤描述
                                                             message:error.localizedDescription
                                                            delegate:nil
                                                   cancelButtonTitle:@"OK"
                                                   otherButtonTitles:nil];
            [alert show];
        }
        self.progressview.hidden = YES;
        self.session = nil;
        self.dataTask = nil;
    }
}
@end

Demo效果

暫停-繼續(xù)


取消


參考:http://blog.csdn.net/hello_hwc/article/details/44565115

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容