网络之NSURLSession
NSUrlSession参考的这篇博客,自己也调试了它的代码:http://www.it165.net/pro/html/201406/15223.html ,对NSUrlSession还不太理解,先记下笔记,随后慢慢消化
AppDelegate.h
// // AppDelegate.h // NSUrlSession // // Created by City--Online on 15/4/27. // Copyright (c) 2015年 CYW. All rights reserved. // #import <UIKit/UIKit.h> typedef void(^MyBlock)(); @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (copy, nonatomic) MyBlock backgroundURLSessionCompletionHandler; @end
AppDelegate.m
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
self.backgroundURLSessionCompletionHandler = completionHandler;
}
ViewController.m
//
// ViewController.m
// NSUrlSession
//
// Created by City--Online on 15/4/27.
// Copyright (c) 2015年 CYW. All rights reserved.
//
#import "ViewController.h"
#import "AppDelegate.h"
@interface ViewController ()<NSURLSessionDelegate>
@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 ViewController
- (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 currentQueue]];
NSURL *url = [NSURL URLWithString:@"http://assets.sbnation.com/assets/2512203/dogflops.gif"];
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://assets.sbnation.com/assets/2512203/dogflops.gif"];
// 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://assets.sbnation.com/assets/2512203/dogflops.gif"]];
self.resumableTask = [self.urlSession downloadTaskWithRequest:request];
}
[self.sessionDownloadTask resume];
}
#pragma mark 后台下载模式
- (void)didClickBackgroundButtonAction:(UIButton *)button{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://assets.sbnation.com/assets/2512203/dogflops.gif"]];
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 backgroundSessionConfigurationWithIdentifier:@"com.shinobicontrols.BackgroundDownload.BackgroundSession"];
// 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.
}
@end

网络之NSURLSession的更多相关文章
- iOS网络2——NSURLSession使用详解
原文在此 一.整体介绍 NSURLSession在2013年随着iOS7的发布一起面世,苹果对它的定位是作为NSURLConnection的替代者,然后逐步将NSURLConnection退出历史舞台 ...
- iOS开发——网络篇——NSURLSession,下载、上传代理方法,利用NSURLSession断点下载,AFN基本使用,网络检测,NSURLConnection补充
一.NSURLConnection补充 前面提到的NSURLConnection有些知识点需要补充 NSURLConnectionDataDelegate的代理方法有一下几个 - (void)conn ...
- iOS 网络请求NSURLSession
iOS 7 和 Mac OS X 10.9 Mavericks 中一个显著的变化就是对 Foundation URL 加载系统的彻底重构. 现在已经有人在深入苹果的网络层基础架构的地方做研究了,所以我 ...
- iOS开发网络篇-NSURLSession介绍
NSURLSession: 作用: 和NSURLConnection一样 1.负责发送请求,建立客户端和服务器的连接发送数据给服务器 2.并收集来自服务器的响应数据 步骤: 1.创建NSURLSess ...
- iOS之网络请求NSURLSession剖析
2013年的WWDC大会上,苹果推出了NSURLSession,对Foundation URL加载系统进行了彻底的重构,提供了更丰富的API来处理网络请求,如:支持http2.0协议.直接把数据下载到 ...
- Cocoa Touch(五):网络请求 NSURLSession/AFNetworking, GCD, NSURLResquest
NSURLRequest 网络请求的关键的就是NSURLRequest类,它的实例表示了请求报文实体以及请求的缓存策略等等,各种网络框架的最终目标都是把这个对象编译成为请求报文发送出去.下面用一个实例 ...
- NSURLSession访问网络数据
1.NSMutableURLRequest的设置 //创建NSMutableURLRequest对象 NSMutableURLRequest *request = [NSMutableURLReque ...
- IOS网络请求之NSURLSession使用
前言: 无论是Android还是ios都离不开与服务器交互,这就必须用到网络请求,记得在2013年做iOS的时候那时候用的ASIHTTPRequest框架,现在重新捡起iOS的时候ASIHTTPReq ...
- NSURLSession 网络库 - 原生系统送给我们的礼物
大家在进行iOS开发的时候一定会用到网络操作.但由于早期原生的 NSURLConnection 操作起来有很多不便,使得大家更愿意使用第三方库的解决方案,比如鼎鼎大名的 AFNetworking.正是 ...
随机推荐
- 第三天:DOM操作css
基本语法: 引用样式时是在head中,用link,另外需要<div>才能显示 修改样式:按下按钮后,引用的样式部分,颜色变为蓝色 如图下图是更改了样式中hello的颜色 代码如下: < ...
- 七种bond模式说明
第一种模式:mod=0 ,即:(balance-rr) Round-robin policy(平衡抡循环策略) 特点:传输数据包顺序是依次传输(即:第1个包走eth0,下一个包就走eth1….一直循环 ...
- Android-Java-Lock
此篇博客已售票例子为例,所以首先看一个synchronized(同步锁机制)的案例 synchronized(同步锁机制)的案例 package android.java.thread19; /** ...
- [leet code 165]Compare Version Numbers
1 题目 Compare two version numbers version1 and version2.If version1 > version2 return 1, if versio ...
- linux下git远程仓库的搭建
一.服务器环境 ubuntukylin-16.04-server-amd64 二.远程服务器创建一个名字叫git的用户,专门用于管理git仓库. $ adduser git 三.安装git.服务器端和 ...
- Visual Studio Code 显示隐藏的.git文件和目录
在默认设置中,Visual Studio Code 将下列文件文件排除在显示列表中: "files.exclude": { "**/.git": true, & ...
- MySQL--Ansible推送密钥实现免密码登录
从别人网站抄过来,保留自用 场景: 对于需要管理的很多linux服务器,每次登录都输入密码比较痛苦,配置一个跳板机,将本地公钥推送带各访问节点上实现SSH登录 登录账号:admin 本地秘钥路径:/h ...
- Android------------------的快捷键的使用
https://www.cnblogs.com/shidian/p/6937630.html
- 组件基础(参数校验和动态组件、v-once)—Vue学习笔记
最最最后一点关于组件传值的问题. 提醒:本篇内容请使用Vue.js开发版!(附带完成的警告和提示) 1.组件的参数校验 父组件向子组件传值,子组件可以决定传值的一些限制. 比如,子组件指向接收Stri ...
- iOS-自定义NavigationItem返回按钮【pop返回按钮】
在用navigationVC时,返回按钮有时候不想用系统的,这里用继承的方式把按钮替换了,同时也可以实现系统的右滑返回,很简单: 1.创建基类 BasePopViewController 创建一个用于 ...