AFURLSessionManagerを使用して、新しいダウンロードタスクを作成しています。
AFURLSessionManager* manager = ...
NSProgress* p = nil;
NSURLSessionDownloadTask* downloadTask =
[manager downloadTaskWithRequest:request
progress:&p
destination:^NSURL*(NSURL* targetPath, NSURLResponse* response) {...}
completionHandler:^(NSURLResponse* response, NSURL* filePath, NSError* error) {...}
];
[downloadTask resume];
ファイルは正常にダウンロードされますが、進行状況の通知を取得するにはどうすればよいですか?
p
は常にnilに設定されます。そのために issue を提出しました。
また、マネージャーでsetDownloadTaskDidWriteDataBlock
を呼び出そうとしましたが、進捗通知が表示されますが、それらはすべてグループ化されて受信されますafterファイルがダウンロードされました。
AFNetworking 2.0では、この領域はまだ少しバグがあるようです
何か案は?
KVOを使用して、fractionCompleted
オブジェクトのNSProgress
プロパティを監視する必要があります。
NSURL *url = [NSURL URLWithString:@"http://www.hfrmovies.com/TheHobbitDesolationOfSmaug48fps.mp4"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPSessionManager *session = [AFHTTPSessionManager manager];
NSProgress *progress;
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request progress:&progress destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
// …
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
[progress removeObserver:self forKeyPath:@"fractionCompleted" context:NULL];
// …
}];
[downloadTask resume];
[progress addObserver:self
forKeyPath:@"fractionCompleted"
options:NSKeyValueObservingOptionNew
context:NULL];
次に、オブザーバーメソッドを追加します。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"fractionCompleted"]) {
NSProgress *progress = (NSProgress *)object;
NSLog(@"Progress… %f", progress.fractionCompleted);
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
もちろん、keyPath
および/またはobject
パラメータをチェックして、それが観察したいオブジェクト/プロパティであるかどうかを判断する必要があります。
AFURLSessionManager
(AFHTTPSessionManager
の継承元)からsetDownloadTaskDidWriteDataBlock:
メソッドを使用して、ダウンロードの進行状況の更新を受信するためのブロックを設定することもできます。
[session setDownloadTaskDidWriteDataBlock:^(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
NSLog(@"Progress… %lld", totalBytesWritten);
}];
このAFNetworkingメソッドは、NSURLSessionDownloadDelegate
プロトコルからのURLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:
メソッドをより便利なブロックメカニズムにマップします。
ところで、AppleのKVO実装はひどく壊れています。 MAKVONotificationCenter でMike Ashが提案したような、より良い実装を使用することをお勧めします。 AppleのKVOが壊れている理由を読むことに興味がある場合は、Mike Ashによる Key-Value Observing Done Right を読んでください。
私は同様の問題に直面し、解決策を見つけました。
以下のリンクを確認してください: http://cocoadocs.org/docsets/AFNetworking/2.0.1/Categories/UIProgressView+AFNetworking.html
#import <AFNetworking/UIKit+AFNetworking.h>
uIProgressViewで利用可能な追加のメソッドを使用します
setProgressWithDownloadProgressOfTask:animated:
私がやった方法:
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response){
NSURL *documentsDirectoryPath = [NSURL fileURLWithPath:[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) firstObject]];
return [documentsDirectoryPath URLByAppendingPathComponent:[targetPath lastPathComponent]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error){
NSLog(@"File downloaded to: %@", filePath);
}];
[self.progressView setProgressWithDownloadProgressOfTask:downloadTask animated:YES];
[downloadTask resume];
進行状況のあるファイルをダウンロードするには、このコードを使用します
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:@"http://..."];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress)
{
NSLog(@"Progress: %f", downloadProgress.fractionCompleted);
if (progressBlock) {
progressBlock(downloadProgress);
}
} destination:^NSURL *(NSURL *targetPath, NSURLResponse *response)
{
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error)
{
if (response && successBlock) {
successBlock(response,filePath);
}
NSLog(@"File downloaded to: %@", filePath);
}];
[downloadTask resume];
Swiftのシンプルなソリューション:
let sessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
let sessionManager = AFURLSessionManager(sessionConfiguration: sessionConfiguration)
let request = NSURLRequest(URL: url)
let sessionDownloadTask = sessionManager.downloadTaskWithRequest(request, progress: nil, destination: { (url, response) -> NSURL in
return destinationPath.URLByAppendingPathComponent(fileName) //this is destinationPath for downloaded file
}, completionHandler: { response, url, error in
//do sth when it finishes
})
2つのオプションがあります。
UIProgressView
およびsetProgressWithDownloadProgressOfTask:
の使用
progressView.setProgressWithDownloadProgressOfTask(sessionDownloadTask, animated: true)
AFURLSessionManager
およびsetDownloadTaskDidWriteDataBlock:
の使用
sessionManager.setDownloadTaskDidWriteDataBlock { session, sessionDownloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
let progress = Float(totalBytesWritten)/Float(totalBytesExpectedToWrite)
//do sth with current progress
}
最後に忘れないでください:
sessionDownloadTask.resume()