【问题标题】:NSURLSessionDownloadTask - downloads but ends with errorNSURLSessionDownloadTask - 下载但以错误结束
【发布时间】:2014-04-12 06:31:24
【问题描述】:

我正在尝试下载 pdf 文件。早些时候,当我使用完成处理程序块时,我能够在 tmp 位置看到文件。然后我想显示下载进度,所以我实现了委托方法。但我现在可以看到进度条正在工作并且正在下载文件。但是一旦下载完成(写入的字节数/总字节数 = 1),就会调用错误委托,并且 tmp 位置中没有文件。我错过了什么?下面是我的代码。我已将项目上传至https://www.dropbox.com/s/vn5zwfwx9izq60a/trydownload.zip

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithURL:[NSURL URLWithString:@"http://aayudham.com/URLLoadingSystem.pdf"]];
    [downloadTask resume];

}

-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    NSLog(@"%@",[error localizedDescription]);
}
-(void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    dispatch_async(dispatch_get_main_queue(), ^{
        _progressBar.progress = (double)totalBytesWritten/(double)totalBytesExpectedToWrite;
        double value =(double)totalBytesWritten/(double)totalBytesExpectedToWrite;
        NSLog(@"%f",value);
    });
}

-(void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{

}

-(void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
       NSError *error;
//getting docs dir path
NSArray * tempArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [tempArray objectAtIndex:0];

//adding folder path
NSString *appDir = [docsDir stringByAppendingPathComponent:@"/Reader/"];

NSFileManager *fileManager = [NSFileManager defaultManager];

if(![fileManager fileExistsAtPath:appDir])
{
    [fileManager createDirectoryAtPath:appDir withIntermediateDirectories:NO attributes:nil error:&error];
}


BOOL fileCopied = [fileManager moveItemAtPath:[location path] toPath:[appDir stringByAppendingString:@"/demo.pdf"] error:&error];

NSLog(fileCopied ? @"Yes" : @"No");
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

【问题讨论】:

  • 你登录didCompleteWithError的错误是什么?
  • 当我打印 [error localizedDescription] 时,我得到“操作无法完成。(Cocoa 错误 516。)”。
  • 我可以通过在toPath 的末尾添加一个文件名来解决这个问题,现在它可以工作了。有没有其他有效的方法来做到这一点?
  • 不确定我是否理解,但也许只是生成一个 UUID 作为文件名就可以了...

标签: objective-c nsurlsession


【解决方案1】:

@Rob 感谢您的及时回复,这对我帮助很大。这是我的有效代码。希望它可以帮助某人。我能够获取实际文件名并使用原始名称将文件移动到我的文档目录。

-(void) URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSError *error;

    //getting application's document directory path
    NSArray * tempArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docsDir = [tempArray objectAtIndex:0];

    //adding a new folder to the documents directory path
    NSString *appDir = [docsDir stringByAppendingPathComponent:@"/Reader/"];

    //Checking for directory existence and creating if not already exists
    if(![fileManager fileExistsAtPath:appDir])
    {
        [fileManager createDirectoryAtPath:appDir withIntermediateDirectories:NO attributes:nil error:&error];
    }

    //retrieving the filename from the response and appending it again to the path
    //this path "appDir" will be used as the target path 
    appDir =  [appDir stringByAppendingFormat:@"/%@",[[downloadTask response] suggestedFilename]];

    //checking for file existence and deleting if already present.
    if([fileManager fileExistsAtPath:appDir])
    {
        NSLog([fileManager removeItemAtPath:appDir error:&error]?@"deleted":@"not deleted");
    }

    //moving the file from temp location to app's own directory
    BOOL fileCopied = [fileManager moveItemAtPath:[location path] toPath:appDir error:&error];
    NSLog(fileCopied ? @"Yes" : @"No");

}

【讨论】:

    【解决方案2】:

    didFinishDownloadingToURL 中,您应该将文件从location 移动到更永久的位置(例如您的文档文件夹)。如果您稍后在临时位置查找该文件,我并不惊讶它不再存在。

    正如the documentation 所说,location 是这样定义的:

    临时文件的文件 URL。由于该文件是临时文件,因此在从此委托方法返回之前,您必须打开文件进行读取或将其移动到应用沙箱容器目录中的永久位置。

    您必须在从didFinishDownloadingToURL 返回之前将文件移动到新位置

    【讨论】:

    • 我正在调试应用程序,一旦下载完成,tmp 文件夹中的文件就会丢失(我不会将它移动到任何地方)。直到下载进度继续我可以看到临时文件出现在 tmp 文件夹中。
    • @Tamil 我已经用文档中的参考更新了我的答案,鼓励您在退出didFinishDownloadingToURL 之前将文件移动到永久位置。操作系统可能会在您从委托方法返回后立即将其删除。
    • 嗨@Rob 非常感谢你,这很有效。但我现在在复制文件时遇到问题。我在文档目录中创建了一个目录并尝试使用 [fileManager copyItemAtPath:[location absoluteString] toPath:newPath error:&error] 将文件移动到那里,但这返回 NO 并且文件未被复制:(
    • @Tamil 就我个人而言,我会使用[fileManager copyItemAtURL:location toURL:[NSURL fileURLWithPath:newPath] error:&error]。但是你看过error 对象吗?这应该告诉你出了什么问题。
    • @SmartHome - 1. 是的,以后请发表您自己的问题。 2.您的错误不是告诉您旧文件已被删除,而是告诉您所选名称的文件已经存在于所需的目标中。 3.您确实应该在调用它的队列上移动文件(或者如果出于同步原因需要另一个队列,请同步调度)。 4. 移动文件(与复制文件不同)非常快,所以不用担心那里的性能问题。 5. 如果您需要另一个队列,请在设置会话时指定。
    【解决方案3】:

    以防万一有人遇到与我相同的问题,我想我会在这里发布我的解决方案。

    我的问题是谓词方法在后台线程上触发,所以我正在分派到我的“文件 io”线程,该线程处理应用程序内的任何文件写入、删除等操作。

    这样做的问题是,一旦委托方法结束,临时文件就会被删除,而这正是在我切换线程的那一刻发生的。因此,当我尝试在我的文件 io 线程中访问该文件时,它已被删除。

    我的解决方案是在委托方法中将文件解析为 NSData,然后在我的文件 io 线程中使用 NSData 写入文件系统。

    【讨论】:

    • 这个答案真的可以使用一些澄清和例子。
    猜你喜欢
    • 2012-01-02
    • 1970-01-01
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    • 2012-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多