Как повысить скорость при использовании NSURLSessionDownloadTask?

Мне нужно загрузить несколько изображений и видео с сервера:

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
for (int i = 0; i < _collectionArr.count; ++i) {

    NSURL *URL = [NSURL URLWithString:URL_ADDRESS(portNumber,_collectionArr[i])];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];

    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil 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) {

        NSLog(@"File downloaded to: %@", filePath);
        if (i == _collectionArr.count - 1) {
            [SVProgressHUD showSuccessWithStatus:@"Done"];
        }

    }];
    [downloadTask resume];
}

Я обнаружил, что это так медленно! Скорость около 200К/с, а время на Android на 2/3 меньше, чем на iPhone. Когда я загружаю mp4 размером около 4,6 МБ, это занимает 15 секунд.

2014-11-29 13:46:35.071 testDownload[2105:47825] Begin
2014-11-29 13:46:51.740 testDownload[2105:47825] File downloaded to: file:///Users/apple/Library/Developer/CoreSimulator/Devices/259F2CB8-01FD-47C2-A38F-6100A2FF350A/data/Containers/Data/Application/71E553BC-F85D-4BFA-8937-FE9026FDF65C/Documents/VTS_01_audi.mp4

Но когда я использую другое приложение для загрузки фильмов, скорость может достигать 2 Мбит/с. Я ошибаюсь, когда использую afnetworking? Как это происходит и что я могу сделать, чтобы справиться с этим. Другой вопрос, что я знаю, что неправильно отслеживать последний запрос с помощью if (i == _collectionArr.count - 1){[SVProgressHUD showSuccessWithStatus:@"Done"];} Но я не знаю правильный ответ.

Спасибо за вашу помощь.


person magic_9527    schedule 29.11.2014    source источник
comment
Смущенный. Я новичок и плохо разбираюсь в блоке. Извиняюсь. И можете ли вы показать мне правильное решение? Большое спасибо.   -  person magic_9527    schedule 29.11.2014
comment
Я скачиваю сингл из фильма, но это было то же самое.   -  person magic_9527    schedule 29.11.2014
comment
К сожалению, я ничего не знаю об AFNetworking. Почему бы вам просто не использовать NSURLSession, который дает вам Apple?   -  person matt    schedule 29.11.2014
comment
@Rob Это медленно, даже если я скачиваю только фильм.   -  person magic_9527    schedule 29.11.2014
comment
@magic_9527 Понятно. Я пока не понимаю, почему это будет медленнее, но я просто пытался отказаться от предложения, что вы могли бы рассмотреть возможность отправки их синхронно, потому что это просто сделает его намного, намного медленнее, если вы будете выполнять несколько загрузок.   -  person Rob    schedule 29.11.2014
comment
Ага, я мало знаю о треде.   -  person magic_9527    schedule 29.11.2014
comment
HUD не закроется, пока миссия не будет выполнена или не истечет время ожидания запроса.   -  person magic_9527    schedule 29.11.2014
comment
Да, есть много вещей, которым нужно научиться, в первую очередь это потоки и блоки. буду пытаться найти причину. Спасибо за ваше предложение.   -  person magic_9527    schedule 29.11.2014


Ответы (1)


Пара мыслей:

  1. Удаление HUD при попадании i в count - 1 некорректно. Вы на самом деле можете удалить его, прежде чем они все будут сделаны. Если вы начнете две загрузки, одну большую и одну крошечную, HUD будет закрыт, когда вторая загрузка завершится, но другая может быть еще не завершена. Они выполняются одновременно, поэтому вам нужно дождаться, пока они все будут выполнены, а не только когда будет выполнен последний отправленный запрос.

    Один из способов сделать это — использовать группу отправки (которую вы вводите при отправке запросов, оставляете в блоке завершения, а затем добавляете уведомление группы отправки, которое удаляет HUD).

  2. Вы не делаете ничего другого, кроме этого кода, который может блокировать основной поток, не так ли? AFNetworking отправляет свои блоки завершения в основную очередь, и если вы заблокируете основной поток для чего-либо, это повлияет на эту производительность. Вы можете либо использовать инструменты для определения ожидающих потоков, либо, только в целях тестирования, временно изменить completionQueue из manager на какую-то пользовательскую очередь, созданную вами.

    Например, перед циклом for сделайте что-то вроде:

    manager.completionQueue = dispatch_queue_create("com.example.app.netCompletionQueue", NULL);
    

    Это исключит блокировку основного потока из уравнения (хотя это кажется мне маловероятным, если только вы не делаете что-то экстраординарное в основном потоке). Однако, как только вы подтвердите, что это не проблема, закомментируйте эту строку, потому что вы действительно хотите использовать основной поток для своих блоков завершения.

  3. Как только вы подтвердите, что проблема с производительностью не связана с конфликтом основного потока, я бы предложил провести бенчмаркинг альтернативных методов (например, ваш собственный NSURLSession и т. д.). Это может помочь диагностировать, связана ли проблема с AFNetworking, а не с чем-то вроде симулятора и производительности устройства, кэширования и т. д. Честно говоря, я считаю маловероятным, что AFNetworking сам по себе является проблемой.

person Rob    schedule 29.11.2014