How can I check that an NSData blob is valid as resumeData for an NSURLSessionDownloadTask?

99封情书 提交于 2019-11-28 19:21:28

问题


I have an app that's using background downloads with the new NSURLSession APIs. When a download cancels or fails in such a way that NSURLSessionDownloadTaskResumeData is provided, I store the data blob so that it can be resumed later. A very small amount of the time I am noticing a crash in the wild:

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

The error occurs here, where resumeData is the NSData blob and session is an instance of NSURLSession:

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

The data is provided by the Apple APIs, is serialized, and is then deserialized at a later point in time. It may be corrupted, but it is never nil (as the if statement checks).

How can I check ahead of time that the resumeData is invalid so that I do not let the app crash?


回答1:


This is the workaround suggested by 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];
}

Edit (iOS 7.1 is not NDA'd anymore): I got this from a Twitter exchange with an Apple engineer, he suggested what to do, and I wrote the above implementation




回答2:


I have not found an answer to how to tell if the data is valid ahead of time.

However, I am presently working around the issue like so:

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
    }
}



回答3:


actually, the resume data is a plist file. it contains the follows key:

  • NSURLSessionDownloadURL
  • NSURLSessionResumeBytesReceived
  • NSURLSessionResumeCurrentRequest
  • NSURLSessionResumeEntityTag
  • NSURLSessionResumeInfoTempFileName
  • NSURLSessionResumeInfoVersion
  • NSURLSessionResumeOriginalRequest
  • NSURLSessionResumeServerDownloadDate so the steps u need to do are:

    1. check the data is a valid plist;
    2. check the plist have keys as above;
    3. check the temp file is exist;


来源:https://stackoverflow.com/questions/21895853/how-can-i-check-that-an-nsdata-blob-is-valid-as-resumedata-for-an-nsurlsessiondo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!