Reputation: 21
So essentially, I'm using a server to retrieve the URLs already stored. Once I retrieve the URL (in a for
loop), I am calling a function that downloads them directly from AWS S3. The issue is that when I only have to download one image at a time, it works perfectly; this includes the case where I am already downloading one image, I upload another, then I go back to the loading home view, and the two images appear properly. When I have multiple images that need downloading (when I first start the app), the images array overlaps. I am using an array for the URL
and another array for the UIImages
.
Here is my ImageCache
code:
class ImageCache {
static var urlCache: Array<String> = []
static var imageCache: Array<UIImage> = []
}
I used this instead of NSCache
is because I need to be able to use imageCache
as my data source and I wasn't sure how to specify the number of objects inside an NSCache
as a NSCache
object isn't iterable.
Anyways, here is the code where I'm calling the download function:
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
}
}
}
The reason for current
and count
is that when the current index equals the last index in the for
loop, then we should update the UICollectionView
. This way the view is reloaded only when the last image is downloaded (at least this was the goal).
And here is my downloadImageFromS3
function:
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
}
}
}
EDIT: I thought I fixed the issue by putting the line
self.collectionView.reloadData()
outside that if
statement I was explaining earlier. This causes the last two images to be messed with, meaning that the first and second image will look fine, but the third and fourth image are the same image. Does anyone have any solutions to make this work?
EDIT: I just found the real issue in why some of the final images are overlapping. I'm getting a decoding error when downloading the image:
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)
I'm under the impression that the error is in this line: let image = UIImage(contentsOfFile: downloadingFileURL.path)!
. The image, upon upload to S3, has Content-Encoding
set to base64
.
Upvotes: 1
Views: 571
Reputation: 21
Solved my own question. Once I changed the downloadingFileURL
path to a .jpeg
file path and made it unique, I was able to see the issue. I was also invoking the wrong initializer for UIImage
. It should've been UIImage(named: downloadingFileURL.path)!
instead of UIImage(contentsOfFile: downloadingFileURL.path)!
Upvotes: 1