Memory issues with UIImage animation image caching

I've been banging my head about this for a few days now and I just can't figure it out. Basically I have a keyboard extension that uses a UICollectionView to display animated UIImages. When it works and I switch to another app and then switch back to the keyboard, I get a splash of around 10MB. This obviously causes the application to crash after multiple swaps.

I've gone through the tools and it looks like I'm getting a bunch of extra UIImages when the keyboard reboots they "end up" clearing up, but it takes time and the cumulative effect maximizes memory. I think it has something to do with UIImage caching the animation image when I start at about 150-200 UIImages, which roughly matches all the animation frames I have in all cells. This pretty much doubles every reboot.

I threw this into the prepareForReuse cell:

override func prepareForReuse() {
    if imageView?.isAnimating() == true {
        NSLog("Stop Animating")
        imageView?.stopAnimating()
    }
    imageView?.animationImages = nil
    contentView.subviews.map({$0.removeFromSuperview()})
    imageRect = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
    imageView = UIImageView(frame: imageRect!)
    type = nil
    super.prepareForReuse()
    imageView?.contentMode = UIViewContentMode.ScaleAspectFit
    contentView.addSubview(imageView!)
}

      

But to no avail. It wasn't even triggered by a reboot. So, new cells are being created, but the old ones are not being cleaned up properly, perhaps?

I tried to run this:

    func clearCellImages(){
    for cell in collectionView.visibleCells(){
        cell.imageView!?.animationImages = nil
        cell.imageView!!.image = nil
    }
}

      

In viewDidDisappear and deinit, but no difference.

It took me a long time to find this issue and now that I have it, I am stumped. Happy to post any code you think will help, very happy to be pointed in the right direction.

Thank.

+3


source to share


1 answer


So it turned out to be a two-way solution. First, I made these little helper functions:

func clearCells(){
    for cell in collectionView.visibleCells(){
        clearCell(cell as! MyCellView)
    }
}

func clearCell(cell:MyCellView){
    if let iv = cell.imageView {
        iv.animationImages = nil
        iv.image = nil
        iv.removeFromSuperview()
    }
}

      

I called clearCells

on viewWillDisappear

and saw a drop in UIImages

and memory usage, however if I scrolled through, which is more than likely, the images that were used in the cells that were currently not visible were not canceled, resulting in a small, but not an insignificant memory creep. I fixed this by calling clearCell

in the delegate method didEndDisplayingCell

:



func collectionView(collectionView: UICollectionView, didEndDisplayingCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
    clearCell(cell as! MyCellView)
}

      

I would really think that such control could be handled, if not automatically with ARC, or with UICollectionView

, and then at least manually through prepareCellForReuse

, but apparently not.

Hope this helps someone :)

+2


source







All Articles