iOS網路編程(六) NSURLSession詳解

來源:互聯網
上載者:User

昨夜瀏覽Demo的時候,看到別人請求網路資料用的是NSURLSession,當時就在想這裡什麼,怎麼沒有用過,引起了我的好奇心,遂去百度-Google-官方文檔一一查看,有了一定的瞭解,原來NSURLSession是iOS7中新的網路介面,它與咱們熟悉的NSURLConnection是並列的。 尋找資料,寫了一個小Demo,大家可以看看,有什麼不足的地方,可以留言幫我指出來.

////  HMTRootViewController.m//  ////  Created by HMT on 14-6-7.//  Copyright (c) 2014年 胡明濤. All rights reserved.//#import "HMTRootViewController.h"#import "HMTAppDelegate.h"@interface HMTRootViewController ()@property (nonatomic,strong)UIImageView *imageView;@property (nonatomic,strong)UIProgressView *progressIndicator;@property (nonatomic,strong)NSURLSession *urlSession;         //  普通會話//@property (nonatomic,strong)NSURLSession *backgroundSession;  //  後台會話@property (nonatomic,strong)NSURLSessionDownloadTask *sessionDownloadTask;  //  下載Task@property (nonatomic,strong)NSURLSessionDownloadTask *resumableTask;        //  恢複下載Task@property (nonatomic,strong)NSURLSessionDownloadTask *backgroundTask;       //  後台下載Task@property (nonatomic,strong)NSData *partialData;   //  下載的局部資料@end@implementation HMTRootViewController- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];    if (self) {        // Custom initialization    }    return self;}- (void)viewDidLoad{    [super viewDidLoad];        self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 64, 320, 300)];    [self.view addSubview:_imageView];        self.progressIndicator = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];    _progressIndicator.frame = CGRectMake(50, 500, 220, 50);    [self.view addSubview:_progressIndicator];        UIButton *cancleButton = [UIButton buttonWithType:UIButtonTypeSystem];    cancleButton.frame = CGRectMake(120, 400, 40, 40);    [cancleButton setTitle:@"取消" forState:UIControlStateNormal];    [cancleButton addTarget:self action:@selector(didClickCancleButtonAction:) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:cancleButton];        UIButton *downloadButton = [UIButton buttonWithType:UIButtonTypeSystem];    downloadButton.frame = CGRectMake(20, 400, 40, 40);    [downloadButton setTitle:@"下載" forState:UIControlStateNormal];    [downloadButton addTarget:self action:@selector(didClickDownloadButtonAction:) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:downloadButton];        UIButton *uploadButton = [UIButton buttonWithType:UIButtonTypeSystem];    uploadButton.frame = CGRectMake(70, 400, 40, 40);    [uploadButton setTitle:@"上傳" forState:UIControlStateNormal];    [uploadButton addTarget:self action:@selector(didClickUploadButtonAction:) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:uploadButton];        UIButton *resumableButton = [UIButton buttonWithType:UIButtonTypeSystem];    resumableButton.frame = CGRectMake(180, 400, 40, 40);    [resumableButton setTitle:@"恢複" forState:UIControlStateNormal];    [resumableButton addTarget:self action:@selector(didClickResuableButtonAction:) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:resumableButton];        UIButton *backgroundLoadButton = [UIButton buttonWithType:UIButtonTypeSystem];    backgroundLoadButton.frame = CGRectMake(220, 400, 80, 40);    [backgroundLoadButton setTitle:@"後台下載" forState:UIControlStateNormal];    [backgroundLoadButton addTarget:self action:@selector(didClickBackgroundButtonAction:) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:backgroundLoadButton];        #pragma mark - 如果我們需要利用NSURLSession進行資料轉送我們需要:    /**     *  建立一個NSURLSessionConfiguration,用於建立NSSession時設定工作模式(3種)     *  (1)一般模式(default):工作模式類似於原來的NSURLConnection,可以使用緩衝的Cache,Cookie,鑒權。     *  (2)及時模式(ephemeral):不使用緩衝的Cache,Cookie,鑒權。     *  (3)後台模式(background):在後台完成上傳下載,建立Configuration對象的時候需要給一個NSString的ID用於追蹤完成工作的Session是哪一個     */    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];        /**     *  @網路設定:參考NSURLConnection中的設定項     *  兩種建立方法(目前不太懂什麼區別)     *  (1)就是根據剛才建立的Configuration建立一個Session,系統預設建立一個新的OperationQueue處理Session的訊息     *  (2)可以設定回調的delegate(注意這個回調delegate會被強引用),並且可以設定delegate在哪個OperationQueue回調,如果我們將其     *     設定為[NSOperationQueue mainQueue]就能在主線程進行回調非常的方便     */    //NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig];    self.urlSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];    NSURL *url = [NSURL URLWithString:@"http://www.bizhiwa.com/uploads/allimg/2012-01/22021207-1-311536.jpg"];    NSURLRequest *request = [NSURLRequest requestWithURL:url];        /**     *  NSURLSessionUploadTask:上傳用的Task,傳完以後不會再下載返回結果;     *  NSURLSessionDownloadTask:下載用的Task;     *  NSURLSessionDataTask:可以上傳內容,上傳完成後再進行下載。     */    self.sessionDownloadTask = [self.urlSession downloadTaskWithRequest:request];    //  同NSURLConnection一樣,有代理方法也就有block方法//    [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {//    }];    }#pragma mark 點擊下載- (void)didClickDownloadButtonAction:(UIButton *)button{    // 因為任務預設是掛起狀態,需要恢複任務(執行任務)    [_sessionDownloadTask resume];}#pragma mark 點擊上傳- (void)didClickUploadButtonAction:(UIButton *)button{    //判斷imageView是否有內容    if (_imageView.image == nil) {                NSLog(@"image view is empty");        return;            }        // 0. 上傳之前在介面上添加指示符    UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];    // 設定位置???    CGSize size = _imageView.bounds.size;    indicator.center = CGPointMake(size.width / 2.0, size.height / 2.0);    [self.imageView addSubview:indicator];    [indicator startAnimating];        // 1. URL    NSURL *url = [NSURL URLWithString:@"http://www.bizhiwa.com/uploads/allimg/2012-01/22021207-1-311536.jpg"];        // 2. Request -> PUT,request的預設操作是GET    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0f];    request.HTTPMethod = @"PUT";        // *** 設定網路請求的身分識別驗證! ***        // 1> 授權字串        NSString *authStr = @"admin:123456";        // 2> BASE64的編碼,避免資料在網路上以明文傳輸    // iOS中,僅對NSData類型的資料提供了BASE64的編碼支援    NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];    NSString *encodeStr = [authData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];    NSString *authValue = [NSString stringWithFormat:@"Basic %@", encodeStr];    [request setValue:authValue forHTTPHeaderField:@"Authorization"];        // 3. Session    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];        // 4. UploadTask    NSData *imageData = UIImageJPEGRepresentation(_imageView.image, 0.75);    //  應用block的請求方式    NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:imageData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {                // 上傳完成後,data參數轉換成string就是伺服器返回的內容                NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];        NSLog(@"OK -> %@", str);        [NSThread sleepForTimeInterval:5.0f];                dispatch_async(dispatch_get_main_queue(), ^{                        [indicator stopAnimating];            [indicator removeFromSuperview];                    });            }];        // 因為任務預設是掛起狀態,需要恢複任務(執行任務)    [uploadTask resume];}#pragma mark 點擊取消//  NSURLConnection一旦發送是沒法取消的。但是,我們可以很容易的取消掉一個NSURLSessionTask任務- (void)didClickCancleButtonAction:(UIButton *)button{    /**     *  當取消後,會回調這個URLSession:task:didCompleteWithError:代理方法,通知你去及時更新UI。當取消一個任務後,也     *  十分可能會再一次回調這個代理方法URLSession:downloadTask:didWriteData:BytesWritten:totalBytesExpectedToWrite:     *  當然,didComplete 方法肯定是最後一個回調的。     *///    if (_sessionDownloadTask) {//        //        //  取消下載請求//        [_sessionDownloadTask cancel];//        _sessionDownloadTask = nil;//    }    if (!self.sessionDownloadTask) {                //  停止下載任務,把待恢複的資料儲存到一個變數中,方便後面恢複下載使用        [self.sessionDownloadTask cancelByProducingResumeData:^(NSData *resumeData) {                       self.partialData = resumeData;            self.sessionDownloadTask = nil;                    }];    }}#pragma mark  恢複下載(斷點續傳)- (void)didClickResuableButtonAction:(UIButton *)button{            if (self.partialData) {                        self.sessionDownloadTask = [self.urlSession downloadTaskWithResumeData:self.partialData];            self.partialData = nil;                    }else{                    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pic4.duowan.com/wow/1002/130782267821/130782458426.jpg"]];            self.resumableTask = [self.urlSession downloadTaskWithRequest:request];                }                [self.sessionDownloadTask resume];}#pragma mark 後台下載模式- (void)didClickBackgroundButtonAction:(UIButton *)button{        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V3.1.2.dmg"]];    self.backgroundTask = [[self backgroundSession] downloadTaskWithRequest:request];        [self.backgroundTask resume];}#pragma mark - NSURLSessionDownloadTaskDelegate//  下載完成- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{    /**      *******->appDelegete裡面的方法     typedef void(^MyBlock)();     @property (copy, nonatomic) MyBlock backgroundURLSessionCompletionHandler;     //  後台請求結束時調用的方法     - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{          self.backgroundURLSessionCompletionHandler = completionHandler;     }          */    //  如果是後台NSURLSession,後台請求結束後會調用這個方法,通知你應該更新UI了    if (session == [self backgroundSession]) {                self.backgroundTask = nil;        HMTAppDelegate *appDelegate = (HMTAppDelegate *)[UIApplication sharedApplication].delegate;        if (appDelegate.backgroundURLSessionCompletionHandler) {                        void(^handler)() = appDelegate.backgroundURLSessionCompletionHandler;            appDelegate.backgroundURLSessionCompletionHandler = nil;            handler();        }            }        //  這裡的緩衝處理做的不好,大家按自己的方法處理就行,還有圖片的儲存以它本身的URL路徑為準,這樣是不會有重複的    NSFileManager *fileManager = [NSFileManager defaultManager];    NSURL *cachesURLPath = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];    //  根據URL擷取到下載的檔案名稱,拼接成沙箱的儲存路徑(location是下載的臨時檔案目錄,在tmp檔案夾裡面)    NSURL *destinationPath = [cachesURLPath URLByAppendingPathComponent:[location lastPathComponent]];        NSError *error = nil;    BOOL success = [fileManager moveItemAtURL:location toURL:destinationPath error:&error];    [fileManager removeItemAtURL:location error:NULL];        //  location是下載的臨時檔案目錄,將檔案從臨時檔案夾複製到沙箱//    BOOL success = [fileManager copyItemAtURL:location toURL:destinationPath error:&error];    if (success) {                dispatch_async(dispatch_get_main_queue(), ^{                       UIImage *image = [UIImage imageWithContentsOfFile:[destinationPath path]];            self.imageView.image = image;            //  UIImageView會自動裁剪圖片適應它的frame,下面這個屬性就是展示原圖            self.imageView.contentMode = UIViewContentModeScaleAspectFill;                });    }}//  不管任務是否成功,在完成後都會回調這個代理方法- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{        //  如果error是nil,則證明下載是成功的,否則就要通過它來查詢失敗的原因。如果下載了一部分,這個error會包含一個NSData對象,如果後面要恢複任務可以用到    if (error == nil) {                dispatch_async(dispatch_get_main_queue(), ^{                        self.progressIndicator.hidden = YES;        });    }}//  傳輸進度- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{    double currentValue = totalBytesWritten / (double)totalBytesExpectedToWrite;    dispatch_async(dispatch_get_main_queue(), ^{        NSLog(@"%f",currentValue);        self.progressIndicator.hidden = NO;        self.progressIndicator.progress = currentValue;    });}//  未知- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{    }#pragma mark - NSURLSession另一個重要的特性:即使當應用不在前台時,你也可以繼續傳輸任務。當然,我們的會話模式也要為後台模式- (NSURLSession *)backgroundSession{    //  通過給的後台token,我們只能建立一個後台會話,所以這裡使用dispatch once block    static NSURLSession *backgroundSession = nil;    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{                NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.shinobicontrols.BackgroundDownload.BackgroundSession"];        backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];            });        return backgroundSession;}- (void)didReceiveMemoryWarning{    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}/*#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{    // Get the new view controller using [segue destinationViewController].    // Pass the selected object to the new view controller.}*/@end

@不錯的NSURLSession文章
iOS 7系列譯文:忘記NSURLConnection,擁抱NSURLSession吧!



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.