Как я могу проверить, что BLOB-объект NSData действителен как resumeData для NSURLSessionDownloadTask?

У меня есть приложение, которое использует фоновые загрузки с новым NSURLSession API-интерфейсы. Когда загрузка отменяется или дает сбой таким образом, что NSURLSessionDownloadTaskResumeData при условии, я храню данные BLOB-объектов, так что они могут быть возобновлены позже. Очень небольшое количество времени я замечаю аварию в дикой природе:

Fatal Exception: NSInvalidArgumentException
Invalid resume data for background download. Background downloads must use http or https and must download to an accessible file.

Ошибка возникает здесь, где resumeData это NSData капля и session это пример NSURLSession:

if (resumeData) {
    downloadTask = [session downloadTaskWithResumeData:resumeData];
    ...

Данные предоставляются API Apple, сериализуются, а затем десериализуются в более поздний момент времени. Возможно, он поврежден, но никогда не равен нулю (как проверяет оператор if).

Как я могу проверить заранее, что resumeData является недействительным, чтобы я не дал сбой приложению?

3 ответа

Решение

Это обходной путь, предложенный Apple:

- (BOOL)__isValidResumeData:(NSData *)data{
    if (!data || [data length] < 1) return NO;

    NSError *error;
    NSDictionary *resumeDictionary = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:&error];
    if (!resumeDictionary || error) return NO;

    NSString *localFilePath = [resumeDictionary objectForKey:@"NSURLSessionResumeInfoLocalPath"];
    if ([localFilePath length] < 1) return NO;

    return [[NSFileManager defaultManager] fileExistsAtPath:localFilePath];
}

Редактировать (iOS 7.1 больше не NDA): я получил это из обмена Twitter с инженером Apple, он предложил, что делать, и я написал вышеупомянутую реализацию

Я не нашел ответа на вопрос, как определить, действительны ли данные заблаговременно.

Тем не менее, в настоящее время я работаю над этой проблемой так:

NSData *resumeData = ...;
NSURLRequest *originalURLRequest = ...;
NSURLSessionDownloadTask *downloadTask = nil;

@try {
    downloadTask = [session downloadTaskWithResumeData:resumeData];
}
@catch (NSException *exception) {
    if ([NSInvalidArgumentException isEqualToString:exception.name]) {
        downloadTask = [session downloadTaskWithRequest:originalURLRequest];
    } else {
        @throw exception; // only swallow NSInvalidArgumentException for resumeData
    }
}

На самом деле, данные резюме представляют собой файл plist. он содержит следующий ключ:

  • NSURLSessionDownloadURL
  • NSURLSessionResumeBytesReceived
  • NSURLSessionResumeCurrentRequest
  • NSURLSessionResumeEntityTag
  • NSURLSessionResumeInfoTempFileName
  • NSURLSessionResumeInfoVersion
  • NSURLSessionResumeOriginalRequest
  • NSURLSessionResumeServerDownloadDate, поэтому вам нужно выполнить следующие шаги:

    1. проверьте данные действительный список;
    2. проверьте, есть ли у ключей ключи, как указано выше;
    3. проверьте, существует ли временный файл;
Другие вопросы по тегам