I have an UICollectionView where there is an image in each cell. These image are loaded in by an URL. But when an cell is scroll out of view it show another cell's image for a second before loading is own again. I don't know why this is happening.
Here is my code:
My UIImageView extension to load from url:
extension UIImageView {
public func imageFromUrl(urlString: String) {
Alamofire.request(.GET, urlString).responseJSON{
response in
if let tilbudimage = UIImage(data: response.data!){
self.image = tilbudimage
}
}
}
}
UICollectionView:
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(DealArr.count)
return DealArr.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("DealCell", forIndexPath: indexPath) as! DealCell
let deal = self.DealArr[indexPath.row]
cell.backgroundColor = UIColor.whiteColor()
cell.DealImage.imageFromUrl(deal["image"].string!)
cell.DealLabel.text = deal["title"].string! + ", " + String(deal["price"].int!) + "kr."
cell.DealDescription.text = deal["description"].string!
cellarr.append(cell)
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(collectionView.frame.width, 450)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(0, 0, 0, 0)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat {
return 0.0
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAtIndex section: Int) -> CGFloat {
return 1.0
}
You aren't clearing out the image when the cell is displayed. Cells get reused after they are removed from the screen, so before displaying you need to make sure you clear out any data that shouldn't be carried over. Usually this is handled by setting any data to the new values. In the case of your image, instead of immediately setting the new image, it dispatches an asynchronous task to fetch the image, then it shows that image in the cell. So the image will get reassigned, but it will wait until it receives a response from the server with the new image before clearing out the old image.
To fix this, you should set the image equal to nil before loading the new image.
cell.DealImage.image = nil
cell.DealImage.imageFromUrl(deal["image"].string!)
Or your extension could also start by clearing the image before loading the new one.
extension UIImageView {
public func imageFromUrl(urlString: String) {
image = nil
Alamofire...
You can also improve the efficiency of the loading by cancelling any pending requests when reusing a cell. There's a good tutorial that includes this on raywenderlich if you're interested: http://www.raywenderlich.com/85080/beginning-alamofire-tutorial
You can also improve performance by caching the images after they've been downloaded. For that you can use an instance of NSCache.
let imageCache = NSCache()
extension UIImageView {
public func imageFromUrl(urlString: String) {
if let image = imageCache.objectForKey(urlString) as? UIImage {
self.image = image
}
else {
Alamofire.request(.GET, urlString).responseJSON{
response in
if let tilbudimage = UIImage(data: response.data!){
self.image = tilbudimage
imageCache.setObject(tilbudimage, forKey: urlString)
}
}
}
}
}