NSURLSession-demo

 

#import "ViewController.h"缓存

#import "AppDelegate.h"服务器

@interface ViewController ()网络

 

@property (nonatomic,strong)UIImageView *imageView;session

@property (nonatomic,strong)UIProgressView *progressIndicator;app

 

@property (nonatomic,strong)NSURLSession *urlSession;         //  普通会话async

@property (nonatomic,strong)NSURLSession *backgroundSession;  //  后台会话ide

@property (nonatomic,strong)NSURLSessionDownloadTask *sessionDownloadTask;  //  下载Task编码

@property (nonatomic,strong)NSURLSessionDownloadTask *resumableTask;        //  恢复下载Taskatom

@property (nonatomic,strong)NSURLSessionDownloadTask *backgroundTask;       //  后台下载Taskurl

@property (nonatomic,strong)NSData *partialData;   //  下载的局部数据

 

@property (copy, nonatomic) MyBlock backgroundURLSessionCompletionHandler;

 

@end

 

@implementation ViewController

 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

    if (self) {

        

    }

    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;

//        AppDelegate *appDelegate = (AppDelegate *)[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;

}

 

 

 

 

 

@end

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息