I have a UICollectionView that shows cells at fullscreen (i.e. a gallery). Sometimes, when swiping for the new image, an image other than the right one is displayed for less than a second, than the image is updated. Other times, the wrong image is shown, but if you swipe left and than right (i.e. the image disappear and reappear) than the right image comes up. I don't understand the cause of this behavior. Images are downloaded asynchronously when the collection view needs them. Here is the code:
let blank = UIImage(named: "blank.png")
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! UICollectionViewCell
let image = images[indexPath.row]
if let imageView = cell.viewWithTag(5) as? UIImageView {
imageView.image = blank
if let cachedImage = cache.objectForKey(image.url) as? UIImage {
imageView.image = cachedImage
} else {
UIImage.asyncDownloadImageWithUrl(image.url, completionBlock: { (succeded, dimage) -> Void in
if succeded {
self.cache.setObject(dimage!, forKey: image.url)
imageView.image = dimage
}
})
}
}
return cell
}
where UIImage.asyncDownloadImageWithUrl is:
extension UIImage {
static func asyncDownloadImageWithUrl(url: NSURL, completionBlock: (succeeded: Bool, image: UIImage?) -> Void) {
let request = NSMutableURLRequest(URL: url)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: { (response, data, error) in
if error == nil {
if let image = UIImage(data: data) {
completionBlock(succeeded: true, image: image)
}
} else {
completionBlock(succeeded: false, image: nil)
}
})
}
}
and for the first image shown:
func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
if let index = self.index {
let newIndexPath = NSIndexPath(forItem: index, inSection: 0)
self.collectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false)
self.index = nil
}
}
This is what i think it's happening:
This is happening because you are not keeping track of which image url should load on the completion block.
Try this:
One way to do that is to store the url of the image that should be there in your UICollectionViewCell. To do that, create a subclass:
class CustomCollectionViewCell:UICollectionViewCell {
var urlString = ""
}
Then:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CustomCollectionViewCell
let image = images[indexPath.row]
if let imageView = cell.viewWithTag(5) as? UIImageView {
imageView.image = blank
cell.urlString = image.url.absoluteString
if let cachedImage = cache.objectForKey(image.url) as? UIImage {
imageView.image = cachedImage
} else {
UIImage.asyncDownloadImageWithUrl(image.url, completionBlock: { (succeded, dimage) -> Void in
if succeded {
self.cache.setObject(dimage!, forKey: image.url)
//
// This can happen after the cell has dissapeared and reused!
// check that the image.url matches what is supposed to be in the cell at that time !!!
//
if cell.urlString == image.url.absoluteString {
imageView.image = dimage
}
}
})
}
}
return cell
}
For a more accurate reply, post the project (or a barebones version of it). It's a lot of work to reproduce your setup and test.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With