Как возобновить загрузку с помощью MKNetworkKit в случае сбоя сети
Якобы MKNetworkKit поддерживает возобновление прерванных загрузок, но не совсем понятно, как это можно сделать. В другом потоке разработчик говорит, что он работает, если сервер отправляет заголовки Range.
Как отменить или приостановить загрузку MKNetworkKit iOS?
Однако, насколько я понимаю, именно клиент отправляет заголовки Range. Я ожидаю, что библиотека увидит, сколько было загружено, а затем запросит соответствующий диапазон. Я не вижу места в коде, который делает это.
Метод
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
действительно проверяет, был ли указан Range, но, похоже, на самом деле нет никакого кода, выполняющего определение.
Кто-нибудь заставил MKNetworkKit возобновить загрузку после сбоя сети?
1 ответ
Помимо функции freezable, которая, как я понимаю, не работает для GET, в стандартном MKNetworkKit нет способа возобновить загрузку. Однако небольшая модификация позволяет возобновить загрузку, которая была остановлена
beginBackgroundTaskWithExpirationHandler
или
operationFailedWithError
это требует сохранения downloadDataSize в другое свойство, скажем, resumeDownloadedDataSize, и предоставление этого доступа вызывающему объекту с помощью уведомления, такого как
NSDictionary *resumeDownloadedDataSizeDetails = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithLong:self.resumeDownloadedDataSize], @"resumeDownloadedDataSize", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:kMKNetworkOperationEndBackgroundTaskWithExpirationHandler object:self userInfo:resumeDownloadedDataSizeDetails];
(определите kMKNetworkOperationEndBackgroundTaskWithExpirationHandler в MkNetworkKit.h)
Установите для resumeDownloadedDataSize значение 0, где операция завершается без ошибок или прерываний, и установите равным downloadDataSize, когда вы хотите продолжить.
Затем добавьте
if (self.resumeDownloadedDataSize !=0) {
NSString* range = @"bytes=";
range = [range stringByAppendingString:[[NSNumber numberWithLong:self.resumeDownloadedDataSize] stringValue]];
range = [range stringByAppendingString:@"-"];
[[self request] setValue:range forHTTPHeaderField:@"Range"];
}
в
-(void) start
Этот код в начале
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (self.downloadedDataSize == 0) {
// This is the first batch of data
// Check for a range header and make changes as neccesary
NSString *rangeString = [[self request] valueForHTTPHeaderField:@"Range"];
if ([rangeString hasPrefix:@"bytes="] && [rangeString hasSuffix:@"-"]) {
NSString *bytesText = [rangeString substringWithRange:NSMakeRange(6, [rangeString length] - 7)];
self.startPosition = [bytesText integerValue];
self.downloadedDataSize = self.startPosition;
}
}
Теперь работает для моего добавленного смещения, так как клиент запросил диапазон.
Я также добавил
@property (assign, nonatomic) NSUInteger resumeDownloadedDataSize;
в заголовочный файл, чтобы я мог установить его из других представлений.
Теперь в вашем вызывающем объекте вы можете прослушать уведомление
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didMKNetworkOperationEndBackgroundTaskWithExpirationHandler:) name:kMKNetworkOperationEndBackgroundTaskWithExpirationHandler object:nil];
проверьте это для вас и перезапустите операцию, установив диапазон.
- (void) didMKNetworkOperationEndBackgroundTaskWithExpirationHandler: (NSNotification*) notification
{
if ([[notification object] isEqual:downloadOperation]) {
resumeDownloadedDataSize = [notification.userInfo objectForKey:@"resumeDownloadedDataSize"];
bDownloadOperationCancelled=YES;
}
}
Поскольку я использую это для загрузки большого файла, срок действия обработчика истекает, и я перезапускаю операцию, когда возвращаюсь на передний план.
if (bDownloadOperationCancelled) {
NSLogDebug(@"DownloadOperationCancelled restarted");
[self doFileDownload];
bDownloadOperationCancelled=NO;
}
где
- (void) doFileDownload
{
downloadOperation = [ApplicationDelegate.downloadEngine downloadVideoFile:authDownloadURLString toFile:downloadPath withOffset:resumeDownloadedDataSize];
(Your code for handling completion blocks etc)
…
}
Последнее, что нужно сделать, это убедиться, что в вашем движке вы добавляете YES
[op addDownloadStream:[NSOutputStream outputStreamToFileAtPath:filePath append:YES]];
Таким образом, резюме добавляет в файл.
Просто чтобы прояснить ситуацию, я использую AWS CloudFront, и это поддерживает использование заголовков диапазона, когда данные хранятся в S3.
Похоже, это работает для меня. Я уверен, что есть более элегантные способы сделать это.