【问题标题】:NSURLSessionDownloadTask occasionally results in nil dataNSURLSessionDownloadTask 偶尔会导致 nil 数据
【发布时间】:2018-01-11 22:50:01
【问题描述】:

我正在从我的应用程序中的 CDN 异步下载图像(在 UICollectionView 中)。每次我运行它,不同的图像将无法加载。大约 22 个中的 1-3 个。有时(很少)它们都加载。但关键是它并不一致。发生了什么是在这一行:

NSData *fileData = [NSData dataWithContentsOfURL:location];

fileData 是间歇性的 nil 。奇怪的是,NSURLSessionDownloadTask 中的error 也是nil。这是完整的方法:

+ (void) downloadFileAsynchronouslyWithUrl:(NSURL *)fileUrl andCallback:(void (^)(NSData* fileData, NSError* error))callback {
    NSURLSessionDownloadTask *downloadTask = [[NSURLSession sharedSession] downloadTaskWithURL:fileUrl completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (error != nil) {
                NSLog(@"ERROR: %@", error.localizedDescription);
                callback(nil, error);
            }
            else {
                NSData *fileData = [NSData dataWithContentsOfURL:location];
                if (fileData != nil) {
                    callback(fileData, nil);
                }
                else {
                    // Getting this intermittently
                    NSError *err = [self errorFromString:@"downloaded file was nil!"];
                    callback(nil, err);
                }
            }
        });
    }];
    [downloadTask resume];
}

我已经记录了状态码,它总是 200。

这让我很困惑。有什么想法吗?

【问题讨论】:

  • 在加载图像时是否在滚动?如果使用可重复使用的单元格,图像可能会加载到错误的单元格中。
  • @PeterTao 图像位于正确的单元格中 - 我已经将问题追溯到这种方法,就像我说的那样,fileData 导致 nil
  • 在使用第三方库(如github.com/rs/SDWebImage)时是否会出现这种情况?如果请求是通过 Postman 发出的,那么检索到的图像是否一致?
  • @PeterTao 不,不使用任何第三方库。
  • 我在想可能是一次请求太多,而 iOS 无法同时处理那么多...也许我需要限制它们?

标签: ios objective-c asynchronous


【解决方案1】:

您应该确保将文件同步移动到本地(或将其加载到NSData)。当您从此downloadTaskWithURL 完成块返回时,该文件将被删除。您正在尝试从 dispatch_async 中读取此文件,这会在从文件中获取数据与操作系统为您删除此临时文件之间引入竞争条件。

所以,你可以试试这样的:

+ (void) downloadFileAsynchronouslyWithUrl:(NSURL *)fileUrl andCallback:(void (^)(NSData* fileData, NSError* error))callback {
    NSURLSessionDownloadTask *downloadTask = [[NSURLSession sharedSession] downloadTaskWithURL:fileUrl completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error != nil) {
            NSLog(@"ERROR: %@", error.localizedDescription);
            dispatch_async(dispatch_get_main_queue(), ^{
                callback(nil, error);
            });
        }
        else {
            NSData *fileData = [NSData dataWithContentsOfURL:location];
            dispatch_async(dispatch_get_main_queue(), ^{
                if (fileData != nil) {
                    callback(fileData, nil);
                }
                else {
                    // Getting this intermittently
                    NSError *err = [self errorFromString:@"downloaded file was nil!"];
                    callback(nil, err);
                }
            });
        }
    }];
    [downloadTask resume];
}

或者,您可以考虑使用URLSessionDataTask,这样可以避免此问题。当我们试图减少峰值内存使用和/或使用后台会话时,我们通常会使用下载任务,但这些情况都不适用于这里。

【讨论】:

  • 做到了!谢谢。
猜你喜欢
  • 2018-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-12
  • 2011-06-19
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多