大佬教程收集整理的这篇文章主要介绍了ios – AFNetworking 2.0将NSURLSessionDataTask转换为NSURLSessionDownloadTask不会将所有文件数据写入磁盘,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
很长的帖子,感谢阅读和任何建议.
更新2014-09-30 – 最终修复
所以我最近又遇到了同样的行为,并决定深入挖掘.事实证明,Matt T(AFNetworking的作者)发布了一个修改AFURLSessionManager -respondsToSELEctor方法的提交,如果任何OPTIONAL委托调用未设置为Blocks,它将返回NO.提交在这里(问题#1779):https://github.com/AFNetworking/AFNetworking/commit/6951a26ada965edc6e43cf83a4985b88b0f514d2.
因此,您支持使用可选委托的方式是使用覆盖-URLSession的块INSTEAD调用-setTaskDidReceiveAuthenticationChALLENgeBlock:方法(调用您要使用的可选委托的方法):dataTask:didReceiveResponse:completionHandler:method in你的子类.这样做会产生预期的结果.
建立:
我们正在编写一个从Web服务器下载文件的iOS应用程序.这些文件受PHP脚本保护,该脚本验证来自iOS客户端的请求.
我们正在使用AFNetworking 2.0并且正在对发送用户凭据等的API执行初始POST(NSURLSessionDataTask)操作.这是最初的要求:
NSURLSessionDataTask * task = [self POST:API_FULL_SYNC_GETFILE_PATH参数:正文成功:^(NSURLSessionDataTask * task,id responSEObject){..}];
我们有一个自定义类,它继承自AFhttpSessionManager类,其中包含此问题中的所有iOS代码.
服务器接收此请求并对用户进行身份验证.其中一个POST参数是客户端尝试下载的文件.服务器找到文件并将其吐出.为了简单起见,我已经删除了身份验证和一些缓存控制头,但这里是运行的服务器PHP脚本:
$file_name = $callparams['FILename']; $requested_file = "$sync_data_dir/$file_name"; @apache_setenv('no-gzip',1); @ini_set('zlib.output_compression','Off'); set_time_limit(0);` $file_size = filesize($requested_filE); header("Content-Type: application/gzip"); header("Content-transfer-encoding: Binary"); header("Content-Length: {$file_sizE}"); header("Content-Disposition: attachment; filename=\"{$file_name}\""); $read_bytes = readfile($requested_filE);
回到客户端,收到响应并调用NSURLSessionDataDelegate的-URLSession:dataTask:didReceiveResponse:completionHandler:方法.我们检测MIME类型并将任务切换到下载任务:
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler { [super URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler]; /* This transforms a data task into a download taks for certain API calls. check the headers to determine what to do */ if ([response.MIMEType isEqualToString:@"application/gzip"]) { // Convert to download task completionHandler(NSURLSessionResponseBecomeDownload); return; } // conTinue as-is completionHandler(NSURLSessionResponseAllow); }
-URLSession:dataTask:didBecomeDownloadTask:方法被调用.我们使用此方法使用id关联数据任务和下载任务.这样做是为了跟踪数据任务完成处理程序中的下载任务的结果.这个问题不是很重要,但这里是代码:
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask { [super URLSession:session dataTask:dataTask didBecomeDownloadTask:downloadTask]; // Relate the data task with the download task. if (!_downloadTaskIdToDownloadIdTaskMap) { _downloadTaskIdToDownloadIdTaskMap = [NSMutableDictionary Dictionary]; } [_downloadTaskIdToDownloadIdTaskMap setObject:@(dataTask.taskIdentifier) forKey:@(downloadTask.taskIdentifier)]; }
出现问题的地方:
在-URLSession:downloadTask:didFinishDownloadingToURL:方法中,写入的临时文件的大小小于content-length.
我们发现了什么:
A)如果我们实现NSURLSessionTaskDelegate类的URLSession:dataTask:didReceiveData:方法,我们会为我们尝试下载的每个文件准确地观察1次调用.如果文件大于16384字节,则生成的临时文件将缩短该数量.将日志条目放入此方法,我们看到对于大于该文件的文件,数据参数的长度为16384字节.
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { [super URLSession:session dataTask:dataTask didReceiveData:data]; NSMutableDictionary *dataTaskDetails = [_dataTaskDetails objectForKey:@(dataTask.taskIdentifier)]; NSString *filename = dataTaskDetails[@"FILename"]; DDLogDebug(@"Data recieved for file '%@'. Data length %d",filename,data.length); }
B)将日志条目放入URLSession:downloadTask:didWriteData:@R_652_10586@lBytesWritten:@R_652_10586@lBytesExpectedToWrite:NSURLSessionDownloadDelegate类的方法,我们观察对我们尝试下载的每个文件进行一次或多次此方法调用.如果文件<16K,则只显示单个呼叫.如果文件大于16K,我们会收到更多电话.这是方法:
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten @R_652_10586@lBytesWritten:(int64_t)@R_652_10586@lBytesWritten @R_652_10586@lBytesExpectedToWrite:(int64_t)@R_652_10586@lBytesExpectedToWrite { [super URLSession:session downloadTask:downloadTask didWriteData:bytesWritten @R_652_10586@lBytesWritten:@R_652_10586@lBytesWritten @R_652_10586@lBytesExpectedToWrite:@R_652_10586@lBytesExpectedToWrite]; id dataTaskId = [_downloadTaskIdToDownloadIdTaskMap objectForKey:@(downloadTask.taskIdentifier)]; NSMutableDictionary *dataTaskDetails = [_dataTaskDetails objectForKey:dataTaskId]; NSString *filename = dataTaskDetails[@"FILename"]; DDLogDebug(@"File '%@': Wrote %lld bytes. @R_652_10586@l %lld of %lld bytes written.",bytesWritten,@R_652_10586@lBytesWritten,@R_652_10586@lBytesExpectedToWritE); }
例如,下面是单个文件’members.json.gz’的控制台输出.我添加了评论以突出重要的一句话.
[2014-02-24 00:54:16:290][main][I][APIClient.m:syncFullGetFile:withSyncToken:andUserName:andpassword:andCompletedBlock:][Line: 184] API Client requesTing file 'members.json.gz' for session with token 'MToxMzkzMjIxMjM4'. <-- This is the initial request for the file. [2014-02-24 00:54:17:448][NSOperationQueue 0x14eb6380][?][APIClient.m:URLSession:dataTask:didReceiveData:][Line: 542] Data recieved for file 'members.json.gz'. Data length 16384 <-- Initial response,seems to fire BEFORE the conversion to a download task. [2014-02-24 00:54:17:487][NSOperationQueue 0x14eb6380][?][APIClient.m:URLSession:downloadTask:didWriteData:@R_652_10586@lBytesWritten:@R_652_10586@lBytesExpectedToWrite:][Line: 521] File 'members.json.gz': Wrote 16384 bytes. @R_652_10586@l 16384 of 92447 bytes written. <-- Now the data task is a download task. [2014-02-24 00:54:17:517][NSOperationQueue 0x14eb6380][?][APIClient.m:URLSession:downloadTask:didWriteData:@R_652_10586@lBytesWritten:@R_652_10586@lBytesExpectedToWrite:][Line: 521] File 'members.json.gz': Wrote 16384 bytes. @R_652_10586@l 32768 of 92447 bytes written. [2014-02-24 00:54:17:533][NSOperationQueue 0x14eb6380][?][APIClient.m:URLSession:downloadTask:didWriteData:@R_652_10586@lBytesWritten:@R_652_10586@lBytesExpectedToWrite:][Line: 521] File 'members.json.gz': Wrote 16384 bytes. @R_652_10586@l 49152 of 92447 bytes written. [2014-02-24 00:54:17:550][NSOperationQueue 0x14eb6380][?][APIClient.m:URLSession:downloadTask:didWriteData:@R_652_10586@lBytesWritten:@R_652_10586@lBytesExpectedToWrite:][Line: 521] File 'members.json.gz': Wrote 16384 bytes. @R_652_10586@l 65536 of 92447 bytes written. [2014-02-24 00:54:17:568][NSOperationQueue 0x14eb6380][?][APIClient.m:URLSession:downloadTask:didWriteData:@R_652_10586@lBytesWritten:@R_652_10586@lBytesExpectedToWrite:][Line: 521] File 'members.json.gz': Wrote 10527 bytes. @R_652_10586@l 76063 of 92447 bytes written. <-- @R_652_10586@l is short by same 16384 - same number as the initial response. [2014-02-24 00:54:17:573][NSOperationQueue 0x14eb6380][?][APIClient.m:URLSession:downloadTask:didFinishDownloadingToURL:][Line: 472] Temp file size for 'members.json.gz' is 76063 [2014-02-24 00:54:17:573][NSOperationQueue 0x14eb6380][?][APIClient.m:URLSession:downloadTask:didFinishDownloadingToURL:][Line: 485] File 'members.json.gz' downloaded. Reported 92447 of 92447 bytes received. [2014-02-24 00:54:17:574][NSOperationQueue 0x14eb6380][?][APIClient.m:URLSession:downloadTask:didFinishDownloadingToURL:][Line: 490] File size after move for 'members.json.gz' is 76063 [2014-02-24 00:54:17:574][NSOperationQueue 0x14eb6380][E][APIClient.m:URLSession:downloadTask:didFinishDownloadingToURL:][Line: 497] Expected size of file 'members.json.gz' is 92447 but size on disk is 76063. Temp file size is 0.
救命:
我们认为我们做错了什么.也许我们从服务器发送的标头与数据到下载任务开关不一致.也许我们没有正确使用AFNetworking.
有没有人对这种行为有所了解?我们是否应该在URLSession中捕获初始响应主体:dataTask:didReceiveData:在任务切换到下载任务之前?
真正奇怪的是,如果文件低于16K,则没有问题.整个文件都是写的.
所有文件请求都作为数据任务启动,并转换为下载任务.
以上是大佬教程为你收集整理的ios – AFNetworking 2.0将NSURLSessionDataTask转换为NSURLSessionDownloadTask不会将所有文件数据写入磁盘全部内容,希望文章能够帮你解决ios – AFNetworking 2.0将NSURLSessionDataTask转换为NSURLSessionDownloadTask不会将所有文件数据写入磁盘所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。