NSURLSession 学习笔记
最近学习了iOS7的一些新API,特别是NSURLSession着实强大方便很多。这里我参考了一些资料,作了个Demo。
https://github.com/cxjwin/TEST_URLSession.git
下面直接进入主题。
NSURLSession种类有三个:
1.Default sessions behave similarly to other Foundation methods for downloading URLs. They use a persistent disk-based cache and store credentials in the user’s keychain.
ps:Default sessions 和其他的网络请求类似(和NSURLConnection类似),本地可以缓存文件。
2.Ephemeral sessions do not store any data to disk; all caches, credential stores, and so on are kept in RAM and tied to the session. Thus, when your app invalidates the session, they are purged automatically.
ps:Ephemeral sessions 不会存储数据,这样会节约内存,但是每次请求都会重新加在数据,所以适合数据量较少的请求(比如加载一段微博信息)。
3.Background sessions are similar to default sessions, except that a separate process handles all data transfers. Background sessions have some additional limitations, described in “Background Transfer Considerations.”
ps:Background sessions 和 default sessions类似,着重是后台下载或是上传功能,这个也是NSURLSession强大的地方,在APP退到后台以后我们还可以继续下载或是上传,因为它由一个独立的进程在管理(原话:the actual transfer is performed by a separate process),当任务完成后它会激活APP进程,通知任务状态,然后你可以完成一些事情(比如保存下载的数据以便于用户下次进入APP使用)。
NSURLSession 任务类型有三个:
1.Data tasks send and receive data using NSData objects. Data tasks are intended for short, often interactive requests from your app to a server. Data tasks can return data to your app one piece at a time after each piece of data is received, or all at once through a completion handler. Because data tasks do not store the data to a file, they are not supported in background sessions.
ps:Data tasks 主要是数据任务,它会在较短的时间内给予反馈(数据片段传输),你可以自己处理数据,也可以从completion handler获取一个拼接好的数据。Data tasks不能用于Background sessions。
2.Download tasks retrieve data in the form of a file, and support background downloads while the app is not running.
ps:Download tasks 会以文件的形式纪录下数据,你可以对文件进行处理。个人觉得大数据适合这个任务,因为数据量比较,很有可能会涉及暂停、失败、断点续等等的行为。
3.Upload tasks send data (usually in the form of a file), and support background uploads while the app is not running.
这个跟Download tasks类似,因为不好模拟,Demo中没有列举这类tasks的用法。
下面是Demo讲解:
这是后续可以用来暂存数据的字典
self.tempDataDict = [NSMutableDictionary dictionary];
这个是我们自定义的缓存文件夹
NSString *cachePath = @"TestCacheDirectory";
#ifdef DEBUG
NSArray *myPathList = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *myPath = [myPathList objectAtIndex:0];
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
NSString *fullCachePath = [[myPath stringByAppendingPathComponent:bundleIdentifier] stringByAppendingPathComponent:cachePath];
NSLog(@"Cache path: %@\n", fullCachePath);
#endif
NSURLCache *myCache =
[[NSURLCache alloc] initWithMemoryCapacity:20 * kOneMegabyte diskCapacity:100 * kOneMegabyte diskPath:cachePath];
defaultSession会用到自己的缓存文件夹
// defaultConfigObject
// Default sessions behave similarly to other Foundation methods for downloading URLs.
// They use a persistent disk-based cache and store credentials in the user’s keychain.
{
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
defaultConfigObject.timeoutIntervalForResource = kDefaultTimeoutIntervalForResource;
defaultConfigObject.URLCache = myCache;
defaultConfigObject.requestCachePolicy = NSURLRequestReturnCacheDataElseLoad;
self.defaultSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
ephemeralSession因为不会缓存文件,所以不需要设置,其实下载的时候它也会有一个临时文件,但是下载完之后就被删除了。
// ephemeralConfigObject
// Ephemeral sessions do not store any data to disk; all caches, credential stores, and so on are kept in RAM and tied to the session.
// Thus, when your app invalidates the session, they are purged automatically.
{
NSURLSessionConfiguration *ephemeralConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];
ephemeralConfigObject.timeoutIntervalForResource = kDefaultTimeoutIntervalForResource;
self.ephemeralSession = [NSURLSession sessionWithConfiguration:ephemeralConfigObject delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
}
backgroundSession这个不要设置超时限制,因为后台下载会根据你设备的负载程度决定分配给你用于下载的资源,很有可能半天不返回数据。
我测试过程有几次设置超时限制为60秒,导致一直下载失败,可能会是这个原因。
// backgroundConfigObject
// Background sessions are similar to default sessions, except that a separate process handles all data transfers.
// Background sessions have some additional limitations, described in “Background Transfer Considerations.”
{
NSURLSessionConfiguration *backgroundConfigObject = [NSURLSessionConfiguration backgroundSessionConfiguration:kBackgroundSessionIdentifier];
backgroundConfigObject.URLCache = myCache;
backgroundConfigObject.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
self.backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfigObject delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
方法讲解:
使用block处理dataTask
因为不使用代理,所以中间的处理步骤都不会显示,最后通过completionHandler返回数据,我们只要在completionHandler处理数据就行了,
因为background sessions不支持 dataTask所以没法使用
- (void)dataTaskWithThreeSessionsWithBlock
{
// data 会被存储在URLCache里面
// 如果URLCache里面有数据那么会被直接返回
// 当使用block的时候,delegate不会触发
NSURLRequest *request1 = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString1]];
[[self.defaultSession dataTaskWithRequest:request1 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"defaultSession data length : %lu", (unsigned long)[data length]);
}] resume];
// data 不会被存储在URLCache里面
// 每次都是重新下载
NSURLRequest *request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString2]];
[[self.ephemeralSession dataTaskWithRequest:request2 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"ephemeralSession data length : %lu", (unsigned long)[data length]);
}] resume];
// Because data tasks do not store the data to a file, they are not supported in background sessions.
// 不支持backgroundSession
}
使用delegate处理dataTask
delegate处理dataTask可以自己实现一些细节
特别是在NSURLSessionDataDelegate里面我可以将 dataTask 转化为 downloadTask(判断请求数据大小),从而更灵活的使用
但是delegate需要自己处理对数据的保存
- (void)dataTaskWithThreeSessionsWithDelegate
{
NSURLRequest *request1 = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString1]];
NSURLSessionDataTask *task1 = [self.defaultSession dataTaskWithRequest:request1];
NSMutableData *tempData1 = [NSMutableData data];
NSString *dataKey1 = [[NSNumber numberWithUnsignedInteger:task1.taskIdentifier + kDefaultSessionBaseIdentifier] stringValue];
[self.tempDataDict setObject:tempData1 forKey:dataKey1];
[task1 resume];
// 这个不被缓存,完成时缓存delegate不会触发
// 所以推荐使用block获取数据
NSURLRequest *request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString2]];
NSURLSessionDataTask *task2 = [self.ephemeralSession dataTaskWithRequest:request2];
NSMutableData *tempData2 = [NSMutableData data];
NSString *dataKey2 = [[NSNumber numberWithUnsignedInteger:task1.taskIdentifier + kEphemeralSessionBaseIdentifier] stringValue];
[self.tempDataDict setObject:tempData2 forKey:dataKey2];
[task2 resume];
// Because data tasks do not store the data to a file, they are not supported in background sessions.
// 不支持backgroundSession
}
下载任务都是异步的,很方便就实现异步下载
- (void)multiDataTasksWithDefaultSession
{
[[self.defaultSession dataTaskWithURL:[NSURL URLWithString:kTestImageURLString1] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"defaultSession_1 : %lu", (unsigned long)[data length]);
}] resume];
[[self.defaultSession dataTaskWithURL:[NSURL URLWithString:kTestImageURLString2] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"defaultSession_2 : %lu", (unsigned long)[data length]);
}] resume];
[[self.defaultSession dataTaskWithURL:[NSURL URLWithString:kTestImageURLString3] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"defaultSession_3 : %lu", (unsigned long)[data length]);
}] resume];
}
因为ephemeralSession不会存储数据,所以处理数据量少的请求,需要即时更新的请求,比较合适
- (void)multiDataTasksWithEphemeralSession
{
[[self.ephemeralSession dataTaskWithURL:[NSURL URLWithString:kTestImageURLString1] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"ephemeralSession_1 : %lu", (unsigned long)[data length]);
}] resume];
[[self.ephemeralSession dataTaskWithURL:[NSURL URLWithString:kTestImageURLString2] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"ephemeralSession_2 : %lu", (unsigned long)[data length]);
}] resume];
[[self.ephemeralSession dataTaskWithURL:[NSURL URLWithString:kTestImageURLString3] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"ephemeralSession_3 : %lu", (unsigned long)[data length]);
}] resume];
}
使用block处理downloadTask
这里面background sessions 不能使用 block
而且使用过程中我发现很多情况是delegate 和 block 只选其一
所以是视情况而定到底哪种适合
个人觉得对于下载来说还是delegate更为适合,因为下载一般时间比较长且用到background sessions的机会比较多
- (void)downloadTaskWithThreeSessionsWithBlock
{
// tmp目录,这两个都没有被存贮,下完就被删除了,所以自己存一下文件
NSURLRequest *request1 = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString1]];
[[self.defaultSession downloadTaskWithRequest:request1 completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSLog(@"defaultSession : %@, %lu", location, (unsigned long)[[NSData dataWithContentsOfURL:location] length]);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *cacheDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"];
NSString *fileName = [location lastPathComponent];
//[[[location lastPathComponent] stringByDeletingPathExtension] stringByAppendingPathExtension:@"jpeg"];
NSString *cacheFile = [cacheDir stringByAppendingPathComponent:fileName];
NSURL *cacheFileURL = [NSURL fileURLWithPath:cacheFile];
NSError *_error = nil;
if ([fileManager moveItemAtURL:location
toURL:cacheFileURL
error:&_error]) {
/* Store some reference to the new URL */
} else {
/* Handle the error. */
NSLog(@"error : %@", [_error localizedDescription]);
}
}] resume];
NSURLRequest *request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString2]];
[[self.ephemeralSession downloadTaskWithRequest:request2 completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSLog(@"ephemeralSession : %@, %lu", location, (unsigned long)[[NSData dataWithContentsOfURL:location] length]);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *cacheDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"];
NSString *fileName = [location lastPathComponent];
//[[[location lastPathComponent] stringByDeletingPathExtension] stringByAppendingPathExtension:@"jpeg"];
NSString *cacheFile = [cacheDir stringByAppendingPathComponent:fileName];
NSURL *cacheFileURL = [NSURL fileURLWithPath:cacheFile];
NSError *_error = nil;
if ([fileManager moveItemAtURL:location
toURL:cacheFileURL
error:&_error]) {
/* Store some reference to the new URL */
} else {
/* Handle the error. */
NSLog(@"error : %@", [_error localizedDescription]);
}
}] resume];
// !!! : Completion handler blocks are not supported in background sessions. Use a delegate instead.
}
使用delegate处理downloadTask,具体处理见Delegate方法
- (void)downloadTaskWithThreeSessionsWithDelegate
{
NSURLRequest *request1 = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString1]];
[[self.defaultSession downloadTaskWithRequest:request1] resume];
NSURLRequest *request2 = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString2]];
[[self.ephemeralSession downloadTaskWithRequest:request2] resume];
NSURLRequest *request3 = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString3]];
[[self.backgroundSession downloadTaskWithRequest:request3] resume];
}
backgroundSession使用delegate处理downloadTask,具体处理见Delegate方法
这个pdf还是比较大的,所以耐心等待一会,下载完成后对应的代理就会返回
- (void)downloadTaskWithBackgroundSessionWithDelegate
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestPdfURLString2]];
NSURLSessionDownloadTask *downloadTask =
[self.backgroundSession downloadTaskWithRequest:request];
[downloadTask resume];
}
判断的规则可以自己定
// 当然如果如果数据比较大,你可以选择将dataTask转为downloadTask
// 这里我先判断类型,时pdf的话就下载
- (void)changeDataTaskToDownloadTask
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestPdfURLString2]];
NSURLSessionDataTask *dataTask =
[self.defaultSession dataTaskWithRequest:request];
[dataTask resume];
}
这里我一直没有找到比较好的办法,查看是否所有的任务都完成了
所以我就用的最笨的方法,检查剩余的任务量
当downloadTasks count == 0 的时候那么所获没有可执行任务了,
这时候就说明所有的下载都已经完成,那么就做你该做的事情吧
- (void)multiDownloadTasksWithEphemeralSession
{
[[self.ephemeralSession downloadTaskWithURL:[NSURL URLWithString:kTestImageURLString1] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSLog(@"1 : %@", location);
[self.ephemeralSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
NSLog(@"downloadTasks count : %d", [downloadTasks count]);
}];
}] resume];
[[self.ephemeralSession downloadTaskWithURL:[NSURL URLWithString:kTestImageURLString2] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSLog(@"2 : %@", location);
[self.ephemeralSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
NSLog(@"downloadTasks count : %d", [downloadTasks count]);
}];
}] resume];
[[self.ephemeralSession downloadTaskWithURL:[NSURL URLWithString:kTestImageURLString3] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSLog(@"3 : %@", location);
[self.ephemeralSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
NSLog(@"downloadTasks count : %d", [downloadTasks count]);
}];
}] resume];
}
对于相同的请求一般NSURLSession不会进行判断的,所以需要自己判断一下,同样的请求会同时发送
当然有一些请求如果NSURLSession已经缓存了数据那么下次调用的时候 NSURLSession会直接取缓存里面的数据
不会再次向网络请求,从而节约流量
这里就要视NSURLSession类型而定了
- (void)sameDownloadTasksWithDefaultSessionSeveralTime
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:kTestImageURLString1]];
NSURLSessionDownloadTask *task = [self.defaultSession downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSLog(@"ephemeralSession_1 : %@", location);
}];
[task resume];
[self.defaultSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDownloadTask *_task in downloadTasks) {
if ([[[_task currentRequest] URL] isEqual:[NSURL URLWithString:kTestImageURLString1]]) {
NSLog(@"same request....");
}
}
}];
[[self.defaultSession downloadTaskWithURL:[NSURL URLWithString:kTestImageURLString1] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSLog(@"ephemeralSession_2 : %@", location);
}] resume];
}
后台下载完成后会触发这个方法
执行一些自定义的处理后,调用appDelegate.completionHandler告诉APP已经处理完了
#pragma mark -
#pragma mark - NSURLSessionDelegate
/* If an application has received an
* -application:handleEventsForBackgroundURLSession:completionHandler:
* message, the session delegate will receive this message to indicate
* that all messages previously enqueued for this session have been
* delivered. At this time it is safe to invoke the previously stored
* completion handler, or to begin any internal updates that will
* result in invoking the completion handler.
*/
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
NSLog(@"%s, %d", __func__, __LINE__);
AppDelegate *appDelegate = (id)[[UIApplication sharedApplication] delegate];
BackgroundCompletionHandler handler = appDelegate.completionHandler;
if (handler) {
handler();
}
}
typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {
NSURLSessionResponseCancel = 0, /* Cancel the load, this is the same as -[task cancel] */
NSURLSessionResponseAllow = 1, /* Allow the load to continue */
NSURLSessionResponseBecomeDownload = 2, /* Turn this request into a download */
} NS_ENUM_AVAILABLE(10_9, 7_0);
这里我们可以选择到底是 退出,转下载,还是允许
#pragma mark -
#pragma mark - NSURLSessionDataDelegate
/* The task has received a response and no further messages will be
* received until the completion block is called. The disposition
* allows you to cancel a request or to turn a data task into a
* download task. This delegate message is optional - if you do not
* implement it, you can get the response as a property of the task.
*/
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler
{
NSLog(@"response MIMEType : %@.", response.MIMEType);
if ([response.MIMEType rangeOfString:@"pdf"].length > 0) {// 如果是pdf的话,文件比较大那么转为下载
NSLog(@"MIMEType is a pdf, so become download");
completionHandler(NSURLSessionResponseBecomeDownload);
} else {
completionHandler(NSURLSessionResponseAllow);
}
}
dataTask已经转为downloadTask
/* Notification that a data task has become a download task. No
* future messages will be sent to the data task.
*/
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
{
NSLog(@"MIMEType is a pdf, has become download");
}
这里我们用字典分别对不同的URLSession进行数据存储
delegate是需要我们自己存储数据的
/* Sent when data is available for the delegate to consume. It is
* assumed that the delegate will retain and not copy the data. As
* the data may be discontiguous, you should use
* [NSData enumerateByteRangesUsingBlock:] to access it.
*/
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
if (session == self.defaultSession) {
NSString *dataKey = [[NSNumber numberWithUnsignedInteger:dataTask.taskIdentifier + kDefaultSessionBaseIdentifier] stringValue];
NSMutableData *tempData = [self.tempDataDict objectForKey:dataKey];
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
[tempData appendBytes:bytes length:byteRange.length];
}];
} else if (session == self.ephemeralSession) {
NSString *dataKey = [[NSNumber numberWithUnsignedInteger:dataTask.taskIdentifier + kEphemeralSessionBaseIdentifier] stringValue];
NSMutableData *tempData = [self.tempDataDict objectForKey:dataKey];
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
[tempData appendBytes:bytes length:byteRange.length];
}];
}
}
ephemeralSession貌似不会触发这个
所以用这个代理来预示是否已经缓存完数据不会很靠谱
/* Invoke the completion routine with a valid NSCachedURLResponse to
* allow the resulting data to be cached, or pass nil to prevent
* caching. Note that there is no guarantee that caching will be
* attempted for a given resource, and you should not rely on this
* message to receive the resource data.
*/
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
willCacheResponse:(NSCachedURLResponse *)proposedResponse
completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler
{
NSString *dataKey = nil;
if (session == self.defaultSession) {
dataKey = [[NSNumber numberWithUnsignedInteger:dataTask.taskIdentifier + kDefaultSessionBaseIdentifier] stringValue];
} else if (session == self.ephemeralSession) {
dataKey = [[NSNumber numberWithUnsignedInteger:dataTask.taskIdentifier + kEphemeralSessionBaseIdentifier] stringValue];
}
NSMutableData *tempData = [self.tempDataDict objectForKey:dataKey];
NSLog(@"taskIdentifier : %@, data length : %lu", dataKey, (unsigned long)[tempData length]);
NSLog(@"proposed response : %@", proposedResponse);
if (proposedResponse) {
completionHandler(proposedResponse);
}
}
我们可以自己处理缓存的路径
注释掉的代码是用默认的缓存文件夹缓存数据
#pragma mark -
#pragma mark - NSURLSessionDownloadDelegate
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *cacheDir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Caches"];
NSString *fileName = [location lastPathComponent];
//[[[location lastPathComponent] stringByDeletingPathExtension] stringByAppendingPathExtension:@"jpeg"];
NSString *cacheFile = [cacheDir stringByAppendingPathComponent:fileName];
NSURL *cacheFileURL = [NSURL fileURLWithPath:cacheFile];
NSError *error = nil;
if ([fileManager moveItemAtURL:location
toURL:cacheFileURL
error:&error]) {
/* Store some reference to the new URL */
} else {
/* Handle the error. */
NSLog(@"error : %@", [error localizedDescription]);
}
// NSCachedURLResponse *cachedURLResponse = [[NSCachedURLResponse alloc] initWithResponse:downloadTask.response data:[NSData dataWithContentsOfURL:location]];
// [session.configuration.URLCache storeCachedResponse:cachedURLResponse forRequest:downloadTask.currentRequest];
NSLog(@"Session %@ download task %@ finished downloading to URL %@\n", session, downloadTask, location);
}
这两个代理显示处理下载的进度
但是APP退到后台后就不会再触发了
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
{
// double p = (double)totalBytesWritten / totalBytesExpectedToWrite;
// NSLog(@"downloadTask : %@, %.1f%%", downloadTask, p * 100.0);
}
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
// NSLog(@"Session %@ download task %@ resumed at offset %lld bytes out of an expected %lld bytes.\n",
// session, downloadTask, fileOffset, expectedTotalBytes);
}