10

我有一个使用新NSURLSessionAPI 进行后台下载的应用程序。当下载以提供的方式取消或失败时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.

错误发生在这里,blob 在哪里并且resumeData是一个实例:NSDatasessionNSURLSession

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

数据由 Apple API 提供,经过序列化,然后在稍后的时间点反序列化。它可能已损坏,但永远不会为零(如 if 语句检查)。

如何提前检查resumeData无效,以免应用程序崩溃?

4

3 回答 3

25

这是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 不再是保密协议):我从与 Apple 工程师的 Twitter 交流中得到了这个,他建议做什么,我写了上面的实现

于 2014-03-03T02:09:09.783 回答
2

我还没有找到如何提前判断数据是否有效的答案。

但是,我目前正在解决这个问题:

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
    }
}
于 2014-02-24T17:58:46.643 回答
1

实际上,简历数据是一个 plist 文件。它包含以下键:

  • NSURLSessionDownloadURL
  • NSURLSessionResumeBytesReceived
  • NSURLSessionResumeCurrentRequest
  • NSURLSessionResumeEntityTag
  • NSURLSessionResumeInfoTempFileName
  • NSURLSessionResumeInfoVersion
  • NSURLSessionResumeOriginalRequest
  • NSURLSessionResumeServerDownloadDate 所以你需要做的步骤是:

    1. 检查数据是否为有效的 plist;
    2. 检查 plist 是否具有上述键;
    3. 检查临时文件是否存在;
于 2015-11-20T01:29:00.813 回答