Ios Can';t一次异步下载多个AWS S3映像

Ios Can';t一次异步下载多个AWS S3映像,ios,swift,amazon-web-services,amazon-s3,decoding,Ios,Swift,Amazon Web Services,Amazon S3,Decoding,所以本质上,我使用服务器来检索已经存储的URL。一旦检索到URL(在for循环中),我将调用一个直接从AWS S3下载它们的函数。问题是,当我一次只需要下载一张图片时,它可以完美地工作;这包括我已经下载了一个图像,我上传了另一个,然后我返回加载主视图,两个图像正确显示。当我有多个图像需要下载时(当我第一次启动应用程序时),图像数组会重叠。我正在为URL使用一个数组,为UIImages使用另一个数组 这是我的ImageCache代码: class ImageCache { static v

所以本质上,我使用服务器来检索已经存储的URL。一旦检索到URL(在
for
循环中),我将调用一个直接从AWS S3下载它们的函数。问题是,当我一次只需要下载一张图片时,它可以完美地工作;这包括我已经下载了一个图像,我上传了另一个,然后我返回加载主视图,两个图像正确显示。当我有多个图像需要下载时(当我第一次启动应用程序时),图像数组会重叠。我正在为
URL
使用一个数组,为
UIImages
使用另一个数组

这是我的
ImageCache
代码:

class ImageCache {
    static var urlCache: Array<String> = []
    static var imageCache: Array<UIImage> = []
}
current
count
的原因是,当当前索引等于
for
循环中的最后一个索引时,我们应该更新
UICollectionView
。这样,只有在下载最后一个图像时才重新加载视图(至少这是目标)

这是我的
下载图像froms3
函数:

query.findObjectsInBackground { (results, error) in
    var imageURL: String = ""
    var count: Int = 1
    if error == nil {
        for result in results! {
            print(result)
            imageURL = result["imageURL"] as! String
            let imageKey = imageURL.components(separatedBy: "/uploads")[1]
            if !ImageCache.urlCache.contains(imageURL) {
                self.downloadImageFromS3(key: "uploads\(imageKey)", count: results!.count, current: count, url: imageURL)
            }
            count += 1
        }
    }
}
func downloadImageFromS3(key: String, count: Int, current: Int, url: String) {
    DispatchQueue.main.async {
        let transferManager = AWSS3TransferManager.default()
        let downloadingFileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("image.png")
        let downloadRequest = AWSS3TransferManagerDownloadRequest()
        downloadRequest!.bucket = "BUCKET_NAME"
        downloadRequest!.key = key
        downloadRequest!.downloadingFileURL = downloadingFileURL
        transferManager.download(downloadRequest!).continueWith(executor: AWSExecutor.mainThread()) { (task) -> Any? in
            if let error = task.error as NSError? {
                if error.domain == AWSS3TransferManagerErrorDomain, let code = AWSS3TransferManagerErrorType(rawValue: error.code) {
                    switch code {
                    case .cancelled, .paused:
                        break
                    default:
                        print("Error downloading: \(String(describing: downloadRequest!.key)) Error: \(error)")
                    }
                } else {
                    print("Error downloading: \(String(describing: downloadRequest!.key)) Error: \(error)")
                }
                return nil
            } else {
                let image = UIImage(contentsOfFile: downloadingFileURL.path)!
                ImageCache.urlCache.append(url)
                ImageCache.imageCache.append(image)
            }
            print("Download complete for: \(String(describing: downloadRequest!.key))")
            if current == count && ImageCache.imageCache.count == count && ImageCache.urlCache.count == count {
                self.collectionView?.reloadData()
                print(ImageCache.imageCache)
                print(ImageCache.urlCache)
            }
            return nil
        }
    }
}
编辑:我想我已经解决了这个问题

self.collectionView.reloadData()
如果我刚才解释的话,那就在
之外。这会导致最后两个图像被弄乱,这意味着第一个和第二个图像看起来很好,但第三个和第四个图像是相同的图像。有没有人有办法让这一切顺利进行

编辑:我刚刚发现了一些最终图像重叠的真正原因。下载图像时出现解码错误:

2018-08-10 22:26:57.826759-0500 PROJECT_NAME[81557:49209786] mapData:754: *** ImageIO - mmapped file changed (old: 8112955  new: 6209998)
2018-08-10 22:26:57.871970-0500 PROJECT_NAME[81557:49209786] [0x7fcf610c5a00] Decoding failed with error code -1
2018-08-10 22:26:57.872127-0500 PROJECT_NAME[81557:49209786] [0x7fcf610c5a00] Decoding: C0 0x10C00B20 0x0218304A 0x11111100 0x00590011 8112955
2018-08-10 22:26:57.872225-0500 PROJECT_NAME[81557:49209786] [0x7fcf610c5a00] Options: 1x-1 [00000000,10C003B6] 0001D060
2018-08-10 22:26:57.872341-0500 PROJECT_NAME[81557:49209786] imageBlockSetCreate:829: *** buffer height mismatch: rect:{0,0,4288,950}  size:{4288,2848}
2018-08-10 22:26:57.873336-0500 PROJECT_NAME[81557:49209786] [Unknown process name] img_blocks_create: Null block
CGImageProviderCopyImageBlockSet(<CGImageProvider 0x6040002ed980> (component-type = Int8, pixel-size = 4, size = [4288 x 2848]));
<CGImageBlockSet 0x6000001357c0> (size = [4288 x 2848], rect = (0, 0) x [4288, 950], count = 3) [1]
2018-08-10 22:26:57.873474-0500 PROJECT_NAME[81557:49209786] [Unknown process name] img_blocks_create: Null block
CGImageProviderCopyImageBlockSet(<CGImageProvider 0x6040002ed980> (component-type = Int8, pixel-size = 4, size = [4288 x 2848]));
<CGImageBlockSet 0x6000001357c0> (size = [4288 x 2848], rect = (0, 0) x [4288, 950], count = 3)
2018-08-10 22:26:57.826759-0500项目名称[81557:49209786]地图数据:754:**ImageIO-地图文件已更改(旧:8112955新:620998)
2018-08-10 22:26:57.871970-0500项目名称[81557:49209786][0x7fcf610c5a00]解码失败,错误代码为-1
2018-08-10 22:26:57.872127-0500项目名称[81557:49209786][0x7fcf610c5a00]解码:C0 0x10C00B20 0x0218304A 0x11100 0x00590018112955
2018-08-10 22:26:57.872225-0500项目名称[81557:49209786][0x7fcf610c5a00]选项:1x-1[00000000,10C003B6]0001D060
2018-08-10 22:26:57.872341-0500项目名称[81557:49209786]图像块集创建:829:**缓冲区高度不匹配:rect:{0,04288950}大小:{42882848}
2018-08-10 22:26:57.873336-0500项目名称[81557:49209786][未知流程名称]img_块创建:空块
CGImageProviderCopyImageBlockSet((组件类型=Int8,像素大小=4,大小=[4288 x 2848]);
(大小=[4288 x 2848],矩形=(0,0)x[4288950],计数=3)[1]
2018-08-10 22:26:57.873474-0500项目名称[81557:49209786][未知流程名称]img_块创建:空块
CGImageProviderCopyImageBlockSet((组件类型=Int8,像素大小=4,大小=[4288 x 2848]);
(大小=[4288x2848],矩形=(0,0)x[4288950],计数=3)

我的印象是错误在这一行:
let image=UIImage(contentsOfFile:downloadingFileURL.path)。上传到S3后,图像的
内容编码
设置为
base64

解决了我自己的问题。一旦我将
下载文件URL
路径更改为
.jpeg
文件路径并使其唯一,我就能够看到问题。我还为
UIImage
调用了错误的初始值设定项。它应该是
UIImage(名为:downloadingFileURL.path)
而不是
UIImage(contentsOfFile:downloadingFileURL.path)

只要看看你的下载内容,我就会使用
guard
语句,而不是强制打开你的下载请求。另外,对于下载,我会在后台队列而不是主队列上进行,只有在您更新UI时才获取主队列。@Adrian我应该将整个下载功能放在后台队列中吗?类似于:func download(){DispatchQueue.global(qos:.background).async{//main code DispatchQueue.main.async{self.collectionView.reloadData()}}}}如果我是你,我会把它放在后台队列中,以便释放主队列进行UI更新。当您更新UI时,您将获取主队列。