web-dev-qa-db-ja.com

NSURLSessionDownloadTaskを使用して同時ダウンロード数を設定する

新しいNSURLSession APIを使用しており、ユーザーがファイルをダウンロードできるようにしています。 NSURLSessionで同時に実行するダウンロードの数を指定したいのですが、実行する方法がわかりません。自分でダウンロードタスクを管理しないようにしたいと思います。許可する数をシステムに通知できれば、はるかに良いでしょう。これは、アプリが実行されていないときにバックグラウンドダウンロードをキューに入れるのにも適しています。これを行う方法はありますか?

25
Cory Imdieke

NSURLSessionConfigurationプロパティを使用してHTTPMaximumConnectionsPerHostオブジェクトに設定できます。

19
CouchDeveloper

このタイムアウトの回避策を見つけました。

デバイスの低速接続シミュレーションでファイルをダウンロードしようとしました(設定->開発者->ネットワークリンクコンディショナー->プロファイルの選択-> 3G->有効化)。

これが私のサンプルコードです:

- (void) methodForNSURLSession{
  NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
  _tasksArray = [[NSMutableArray alloc] init];
  sessionConfig.HTTPMaximumConnectionsPerHost = 3;
  sessionConfig.timeoutIntervalForResource = 120;
  sessionConfig.timeoutIntervalForRequest = 120;
  NSURLSession* session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];

  // data tasks
  [self createDownloadTasksWithSession:session];

}

- (void) createDownloadTasksWithSession:(NSURLSession *)session{
  for (int i = 0; i < 100; i++) {
    NSURLSessionDownloadTask *sessionDownloadTask = [session downloadTaskWithURL: [NSURL URLWithString:@"https://discussions.Apple.com/servlet/JiveServlet/showImage/2-20930244-204399/iPhone%2B5%2BProblem2.jpg"]];
    [_tasksArray addObject:sessionDownloadTask];
    [sessionDownloadTask addObserver:self forKeyPath:@"countOfBytesReceived" options:NSKeyValueObservingOptionOld context:nil];
    [sessionDownloadTask resume];
  }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
  if([[change objectForKey:@"old"] integerValue] == 0){
    NSLog(@"task %d: started", [_tasksArray indexOfObject: object]);
  }
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    if (!error) {
      NSLog(@"task %d: finished!", [_tasksArray indexOfObject:task]);
    } else if (error.code == NSURLErrorTimedOut) {
      NSLog(@"task %d: timed out!", [_tasksArray indexOfObject:task]);
    }
}

そして私の出力:

2014-01-10 10:38:48.769 TestApplication[2442:1803] task 1: started
2014-01-10 10:38:49.517 TestApplication[2442:1803] task 2: started
2014-01-10 10:38:50.273 TestApplication[2442:4b03] task 0: started
2014-01-10 10:40:11.794 TestApplication[2442:5003] task 2: finished!
2014-01-10 10:40:13.924 TestApplication[2442:1803] task 3: started
2014-01-10 10:40:26.221 TestApplication[2442:1d0f] task 1: finished!
2014-01-10 10:40:28.487 TestApplication[2442:1d0f] task 4: started
2014-01-10 10:40:43.007 TestApplication[2442:440f] task 5: timed out!
2014-01-10 10:40:43.009 TestApplication[2442:440f] task 6: timed out!
2014-01-10 10:40:43.011 TestApplication[2442:440f] task 7: timed out!
...

ご覧のとおり、開始されたタスクは2分後にタイムアウトします

timeoutIntervalForResourceおよびtimeoutIntervalForRequestパラメータを使用して遊んだところ、両方を0に設定した場合、タイムアウトなしでダウンロードされます。しかし、バッテリーが消耗しているので、それは良い考えではないと思います。 10分ぐらいでいいと思います。ただし、両方のパラメーターを同じ値に設定する必要があります。

Appleドキュメント:

timeoutIntervalForRequest-追加のデータを待機するときに使用するタイムアウト間隔。 timeoutIntervalForResource-リソース要求にかかる最大時間(1つのリソースに対するすべてのタスクのタイムアウト)

奇妙なことに気づきました:timeoutIntervalForResource = 60およびtimeoutIntervalForRequest = 30、タスクは30秒後にタイムアウトします!しかし、それらのほとんどは起動しません!

タスクが再開したときにtimeoutIntervalForRequestのタイマーが開始したようです。その場合、すべてのタスクを同じ時間に再開し、各タスクのタイムアウトはリソースタイムアウトでなければなりません。

また、ダウンロードタスクを使用したバックグラウンドセッションに関する優れたデモで wwdc13 705セッション をアドバイスできます。

13
kaspartus