Как я могу проверить, что 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, поэтому вам нужно выполнить следующие шаги:
- проверьте данные действительный список;
- проверьте, есть ли у ключей ключи, как указано выше;
- проверьте, существует ли временный файл;