iOS网络编程(六) NSURLSession详解

http://blog.csdn.net/hmt20130412/article/details/29412349

 

昨夜浏览Demo的时候,看到别人请求网络数据用的是NSURLSession,当时就在想这里什么,怎么没有用过,引起了我的好奇心,遂去百度-谷歌-官方文档一一查看,有了一定的了解,原来NSURLSession是iOS7中新的网络接口,它与咱们熟悉的NSURLConnection是并列的。

      查找资料,写了一个小Demo,大家可以看看,有什么不足的地方,可以留言帮我指出来.
  1. //   
  2. //  HMTRootViewController.m   
  3. //     
  4. //   
  5. //  Created by HMT on 14-6-7.   
  6. //  Copyright (c) 2014年 胡明涛. All rights reserved.  
  7. //   
  8.   
  9. #import "HMTRootViewController.h"  
  10. #import "HMTAppDelegate.h"   
  11.   
  12.   
  13. @interface HMTRootViewController ()  
  14.   
  15. @property (nonatomic,strong)UIImageView *imageView;  
  16. @property (nonatomic,strong)UIProgressView *progressIndicator;  
  17.   
  18. @property (nonatomic,strong)NSURLSession *urlSession;         //  普通会话  
  19. //@property (nonatomic,strong)NSURLSession *backgroundSession;  //  后台会话  
  20. @property (nonatomic,strong)NSURLSessionDownloadTask *sessionDownloadTask;  //  下载Task  
  21. @property (nonatomic,strong)NSURLSessionDownloadTask *resumableTask;        //  恢复下载Task  
  22. @property (nonatomic,strong)NSURLSessionDownloadTask *backgroundTask;       //  后台下载Task  
  23. @property (nonatomic,strong)NSData *partialData;   //  下载的局部数据  
  24.   
  25. @end  
  26.   
  27. @implementation HMTRootViewController  
  28.   
  29. - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil  
  30. {  
  31.     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];  
  32.     if (self) {  
  33.         // Custom initialization  
  34.     }  
  35.     return self;  
  36. }  
  37.   
  38. - (void)viewDidLoad{  
  39.   
  40.     [super viewDidLoad];  
  41.       
  42.     self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(064320300)];  
  43.     [self.view addSubview:_imageView];  
  44.       
  45.     self.progressIndicator = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];  
  46.     _progressIndicator.frame = CGRectMake(5050022050);  
  47.     [self.view addSubview:_progressIndicator];  
  48.       
  49.     UIButton *cancleButton = [UIButton buttonWithType:UIButtonTypeSystem];  
  50.     cancleButton.frame = CGRectMake(1204004040);  
  51.     [cancleButton setTitle:@"取消" forState:UIControlStateNormal];  
  52.     [cancleButton addTarget:self action:@selector(didClickCancleButtonAction:) forControlEvents:UIControlEventTouchUpInside];  
  53.     [self.view addSubview:cancleButton];  
  54.       
  55.     UIButton *downloadButton = [UIButton buttonWithType:UIButtonTypeSystem];  
  56.     downloadButton.frame = CGRectMake(204004040);  
  57.     [downloadButton setTitle:@"下载" forState:UIControlStateNormal];  
  58.     [downloadButton addTarget:self action:@selector(didClickDownloadButtonAction:) forControlEvents:UIControlEventTouchUpInside];  
  59.     [self.view addSubview:downloadButton];  
  60.       
  61.     UIButton *uploadButton = [UIButton buttonWithType:UIButtonTypeSystem];  
  62.     uploadButton.frame = CGRectMake(704004040);  
  63.     [uploadButton setTitle:@"上传" forState:UIControlStateNormal];  
  64.     [uploadButton addTarget:self action:@selector(didClickUploadButtonAction:) forControlEvents:UIControlEventTouchUpInside];  
  65.     [self.view addSubview:uploadButton];  
  66.       
  67.     UIButton *resumableButton = [UIButton buttonWithType:UIButtonTypeSystem];  
  68.     resumableButton.frame = CGRectMake(1804004040);  
  69.     [resumableButton setTitle:@"恢复" forState:UIControlStateNormal];  
  70.     [resumableButton addTarget:self action:@selector(didClickResuableButtonAction:) forControlEvents:UIControlEventTouchUpInside];  
  71.     [self.view addSubview:resumableButton];  
  72.       
  73.     UIButton *backgroundLoadButton = [UIButton buttonWithType:UIButtonTypeSystem];  
  74.     backgroundLoadButton.frame = CGRectMake(2204008040);  
  75.     [backgroundLoadButton setTitle:@"后台下载" forState:UIControlStateNormal];  
  76.     [backgroundLoadButton addTarget:self action:@selector(didClickBackgroundButtonAction:) forControlEvents:UIControlEventTouchUpInside];  
  77.     [self.view addSubview:backgroundLoadButton];  
  78.       
  79.   
  80.     #pragma mark - 如果我们需要利用NSURLSession进行数据传输我们需要:  
  81.     /** 
  82.      *  创建一个NSURLSessionConfiguration,用于创建NSSession时设置工作模式(3种) 
  83.      *  (1)一般模式(default):工作模式类似于原来的NSURLConnection,可以使用缓存的Cache,Cookie,鉴权。 
  84.      *  (2)及时模式(ephemeral):不使用缓存的Cache,Cookie,鉴权。 
  85.      *  (3)后台模式(background):在后台完成上传下载,创建Configuration对象的时候需要给一个NSString的ID用于追踪完成工作的Session是哪一个 
  86.      */  
  87.     NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];  
  88.       
  89.     /** 
  90.      *  @网络设置:参考NSURLConnection中的设置项 
  91.      *  两种创建方法(目前不太懂什么区别) 
  92.      *  (1)就是根据刚才创建的Configuration创建一个Session,系统默认创建一个新的OperationQueue处理Session的消息 
  93.      *  (2)可以设定回调的delegate(注意这个回调delegate会被强引用),并且可以设定delegate在哪个OperationQueue回调,如果我们将其 
  94.      *     设置为[NSOperationQueue mainQueue]就能在主线程进行回调非常的方便 
  95.      */  
  96.     //NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig];  
  97.     self.urlSession = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];  
  98.     NSURL *url = [NSURL URLWithString:@"http://www.bizhiwa.com/uploads/allimg/2012-01/22021207-1-311536.jpg"];  
  99.     NSURLRequest *request = [NSURLRequest requestWithURL:url];  
  100.       
  101.     /** 
  102.      *  NSURLSessionUploadTask:上传用的Task,传完以后不会再下载返回结果; 
  103.      *  NSURLSessionDownloadTask:下载用的Task; 
  104.      *  NSURLSessionDataTask:可以上传内容,上传完成后再进行下载。 
  105.      */  
  106.     self.sessionDownloadTask = [self.urlSession downloadTaskWithRequest:request];  
  107.   
  108.     //  同NSURLConnection一样,有代理方法也就有block方法  
  109. //    [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {  
  110. //    }];   
  111.       
  112. }  
  113.   
  114. #pragma mark 点击下载   
  115. - (void)didClickDownloadButtonAction:(UIButton *)button{  
  116.   
  117.     // 因为任务默认是挂起状态,需要恢复任务(执行任务)  
  118.     [_sessionDownloadTask resume];  
  119.   
  120. }  
  121.   
  122. #pragma mark 点击上传   
  123. - (void)didClickUploadButtonAction:(UIButton *)button{  
  124.   
  125.     //判断imageView是否有内容   
  126.     if (_imageView.image == nil) {  
  127.           
  128.         NSLog(@"image view is empty");  
  129.         return;  
  130.           
  131.     }  
  132.       
  133.     // 0. 上传之前在界面上添加指示符   
  134.     UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];  
  135.     // 设置位置???   
  136.     CGSize size = _imageView.bounds.size;  
  137.     indicator.center = CGPointMake(size.width / 2.0, size.height / 2.0);  
  138.     [self.imageView addSubview:indicator];  
  139.     [indicator startAnimating];  
  140.       
  141.     // 1. URL   
  142.     NSURL *url = [NSURL URLWithString:@"http://www.bizhiwa.com/uploads/allimg/2012-01/22021207-1-311536.jpg"];  
  143.       
  144.     // 2. Request -> PUT,request的默认操作是GET   
  145.     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0f];  
  146.     request.HTTPMethod = @"PUT";  
  147.       
  148.     // *** 设置网络请求的身份验证! ***   
  149.       
  150.     // 1> 授权字符串   
  151.       
  152.     NSString *authStr = @"admin:123456";  
  153.       
  154.     // 2> BASE64的编码,避免数据在网络上以明文传输   
  155.     // iOS中,仅对NSData类型的数据提供了BASE64的编码支持  
  156.     NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];  
  157.     NSString *encodeStr = [authData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];  
  158.     NSString *authValue = [NSString stringWithFormat:@"Basic %@", encodeStr];  
  159.     [request setValue:authValue forHTTPHeaderField:@"Authorization"];  
  160.       
  161.     // 3. Session   
  162.     NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];  
  163.     NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];  
  164.       
  165.     // 4. UploadTask   
  166.     NSData *imageData = UIImageJPEGRepresentation(_imageView.image0.75);  
  167.     //  应用block的请求方式   
  168.     NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:imageData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {  
  169.           
  170.         // 上传完成后,data参数转换成string就是服务器返回的内容  
  171.           
  172.         NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
  173.         NSLog(@"OK -> %@", str);  
  174.   
  175.         [NSThread sleepForTimeInterval:5.0f];  
  176.           
  177.         dispatch_async(dispatch_get_main_queue(), ^{  
  178.               
  179.             [indicator stopAnimating];  
  180.             [indicator removeFromSuperview];  
  181.               
  182.         });  
  183.           
  184.     }];  
  185.       
  186.     // 因为任务默认是挂起状态,需要恢复任务(执行任务)   
  187.     [uploadTask resume];  
  188. }  
  189.   
  190. #pragma mark 点击取消   
  191. //  NSURLConnection一旦发送是没法取消的。但是,我们可以很容易的取消掉一个NSURLSessionTask任务  
  192. - (void)didClickCancleButtonAction:(UIButton *)button{  
  193.   
  194.     /** 
  195.      *  当取消后,会回调这个URLSession:task:didCompleteWithError:代理方法,通知你去及时更新UI。当取消一个任务后,也 
  196.      *  十分可能会再一次回调这个代理方法URLSession:downloadTask:didWriteData:BytesWritten:totalBytesExpectedToWrite: 
  197.      *  当然,didComplete 方法肯定是最后一个回调的。 
  198.      */  
  199. //    if (_sessionDownloadTask) {  
  200. //           
  201. //        //  取消下载请求   
  202. //        [_sessionDownloadTask cancel];   
  203. //        _sessionDownloadTask = nil;  
  204. //    }   
  205.   
  206.     if (!self.sessionDownloadTask) {  
  207.           
  208.         //  停止下载任务,把待恢复的数据保存到一个变量中,方便后面恢复下载使用  
  209.         [self.sessionDownloadTask cancelByProducingResumeData:^(NSData *resumeData) {  
  210.              
  211.             self.partialData = resumeData;  
  212.             self.sessionDownloadTask = nil;  
  213.               
  214.         }];  
  215.     }  
  216. }  
  217.   
  218. #pragma mark  恢复下载(断点续传)   
  219. - (void)didClickResuableButtonAction:(UIButton *)button{  
  220.       
  221.         if (self.partialData) {  
  222.               
  223.             self.sessionDownloadTask = [self.urlSession downloadTaskWithResumeData:self.partialData];  
  224.             self.partialData = nil;  
  225.               
  226.         }else{  
  227.           
  228.             NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pic4.duowan.com/wow/1002/130782267821/130782458426.jpg"]];  
  229.             self.resumableTask = [self.urlSession downloadTaskWithRequest:request];  
  230.           
  231.         }  
  232.           
  233.         [self.sessionDownloadTask resume];  
  234.   
  235. }  
  236.   
  237. #pragma mark 后台下载模式   
  238. - (void)didClickBackgroundButtonAction:(UIButton *)button{  
  239.       
  240.     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://dldir1.qq.com/qqfile/QQforMac/QQ_V3.1.2.dmg"]];  
  241.     self.backgroundTask = [[self backgroundSession] downloadTaskWithRequest:request];  
  242.       
  243.     [self.backgroundTask resume];  
  244. }  
  245.   
  246. #pragma mark - NSURLSessionDownloadTaskDelegate  
  247. //  下载完成   
  248. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{  
  249.   
  250.     /** 
  251.       *******->appDelegete里面的方法 
  252.      typedef void(^MyBlock)(); 
  253.      @property (copy, nonatomic) MyBlock backgroundURLSessionCompletionHandler; 
  254.      //  后台请求结束时调用的方法 
  255.      - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{ 
  256.       
  257.      self.backgroundURLSessionCompletionHandler = completionHandler; 
  258.      } 
  259.       
  260.      */  
  261.     //  如果是后台NSURLSession,后台请求结束后会调用这个方法,通知你应该更新UI了  
  262.     if (session == [self backgroundSession]) {  
  263.           
  264.         self.backgroundTask = nil;  
  265.         HMTAppDelegate *appDelegate = (HMTAppDelegate *)[UIApplication sharedApplication].delegate;  
  266.         if (appDelegate.backgroundURLSessionCompletionHandler) {  
  267.               
  268.             void(^handler)() = appDelegate.backgroundURLSessionCompletionHandler;  
  269.             appDelegate.backgroundURLSessionCompletionHandler = nil;  
  270.             handler();  
  271.         }  
  272.           
  273.     }  
  274.       
  275.     //  这里的缓存处理做的不好,大家按自己的方法处理就行,还有图片的存储以它本身的URL路径为准,这样是不会有重复的  
  276.     NSFileManager *fileManager = [NSFileManager defaultManager];  
  277.     NSURL *cachesURLPath = [[fileManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject];  
  278.     //  根据URL获取到下载的文件名,拼接成沙盒的存储路径(location是下载的临时文件目录,在tmp文件夹里面)  
  279.     NSURL *destinationPath = [cachesURLPath URLByAppendingPathComponent:[location lastPathComponent]];  
  280.       
  281.     NSError *error = nil;  
  282.     BOOL success = [fileManager moveItemAtURL:location toURL:destinationPath error:&error];  
  283.     [fileManager removeItemAtURL:location error:NULL];  
  284.       
  285.     //  location是下载的临时文件目录,将文件从临时文件夹复制到沙盒  
  286. //    BOOL success = [fileManager copyItemAtURL:location toURL:destinationPath error:&error];  
  287.     if (success) {  
  288.           
  289.         dispatch_async(dispatch_get_main_queue(), ^{  
  290.              
  291.             UIImage *image = [UIImage imageWithContentsOfFile:[destinationPath path]];  
  292.             self.imageView.image = image;  
  293.             //  UIImageView会自动裁剪图片适应它的frame,下面这个属性就是展示原图  
  294.             self.imageView.contentMode = UIViewContentModeScaleAspectFill;  
  295.           
  296.         });  
  297.     }  
  298.   
  299. }  
  300.   
  301. //  不管任务是否成功,在完成后都会回调这个代理方法   
  302. - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{  
  303.       
  304.     //  如果error是nil,则证明下载是成功的,否则就要通过它来查询失败的原因。如果下载了一部分,这个error会包含一个NSData对象,如果后面要恢复任务可以用到  
  305.     if (error == nil) {  
  306.           
  307.         dispatch_async(dispatch_get_main_queue(), ^{  
  308.               
  309.             self.progressIndicator.hidden = YES;  
  310.         });  
  311.     }  
  312.   
  313. }  
  314.   
  315. //  传输进度   
  316. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{  
  317.   
  318.     double currentValue = totalBytesWritten / (double)totalBytesExpectedToWrite;  
  319.     dispatch_async(dispatch_get_main_queue(), ^{  
  320.         NSLog(@"%f",currentValue);  
  321.         self.progressIndicator.hidden = NO;  
  322.         self.progressIndicator.progress = currentValue;  
  323.     });  
  324. }  
  325.   
  326. //  未知   
  327. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{  
  328.       
  329. }  
  330.   
  331. #pragma mark - NSURLSession另一个重要的特性:即使当应用不在前台时,你也可以继续传输任务。当然,我们的会话模式也要为后台模式  
  332. - (NSURLSession *)backgroundSession{  
  333.   
  334.     //  通过给的后台token,我们只能创建一个后台会话,所以这里使用dispatch once block  
  335.     static NSURLSession *backgroundSession = nil;  
  336.     static dispatch_once_t onceToken;  
  337.     dispatch_once(&onceToken, ^{  
  338.           
  339.         NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.shinobicontrols.BackgroundDownload.BackgroundSession"];  
  340.         backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];  
  341.           
  342.     });  
  343.       
  344.     return backgroundSession;  
  345. }  
  346.   
  347. - (void)didReceiveMemoryWarning  
  348. {  
  349.     [super didReceiveMemoryWarning];  
  350.     // Dispose of any resources that can be recreated.  
  351. }  
  352.   
  353. /* 
  354. #pragma mark - Navigation 
  355.  
  356. // In a storyboard-based application, you will often want to do a little preparation before navigation 
  357. - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
  358. { 
  359.     // Get the new view controller using [segue destinationViewController]. 
  360.     // Pass the selected object to the new view controller. 
  361. } 
  362. */  
  363.   
  364. @end  
//
//  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吧!
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值