Search code examples
iosiphoneswiftuiimageviewuiimage

UIImage created with animatedImageWithImages have bugs?


Recently I found sometimes my gif image not shown. So I write a test code for it:

import UIKit
import ImageIO

extension UIImage {
    static func gifImageArray(data: NSData) -> [UIImage] {
        let source = CGImageSourceCreateWithData(data, nil)!
        let count = CGImageSourceGetCount(source)
        if count <= 1 {
            return [UIImage(data: data)!]
        } else {
            var images = [UIImage]();   images.reserveCapacity(count)
            for i in 0..<count {
                let image = CGImageSourceCreateImageAtIndex(source, i, nil)!
                images.append( UIImage(CGImage: image) )
            }
            return images;
        }
    }

    static func gifImage(data: NSData) -> UIImage? {
        let gif = gifImageArray(data)
        if gif.count <= 1 {
            return gif[0]
        } else {
            return UIImage.animatedImageWithImages(gif, duration: NSTimeInterval(gif.count) * 0.1)
        }
    }
}

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    let _gifData : NSData = NSData(contentsOfURL: NSURL(string: "https://upload.wikimedia.org/wikipedia/commons/d/d3/Newtons_cradle_animation_book_2.gif")!)!
    lazy var _gifImageArray : [UIImage] = UIImage.gifImageArray(self._gifData)
    lazy var _gifImage : UIImage = UIImage.gifImage(self._gifData)!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let table = UITableView(frame: self.view.bounds, style: .Plain)
        table.dataSource = self
        table.delegate = self
        self.view.addSubview(table)
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 1000;
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1;
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let identifier = "cell"
        var cell : UITableViewCell! = tableView.dequeueReusableCellWithIdentifier(identifier);
        if cell == nil {
            cell = UITableViewCell(style: .Default, reuseIdentifier: identifier)
        }

        if let imageView = cell.imageView {
            /** 1. use the same UIImage object created by animatedImageWithImages
                the image disappear when reuse, and when touching cell, it reappear. */
            imageView.image = self._gifImage

            /** 2. create different UIImage by using same image array. this still not work */
//            imageView.image = UIImage.animatedImageWithImages(self._gifImageArray, duration: NSTimeInterval(self._gifImageArray.count) * 0.1)

            /** 3. create different UIImage from data, this seems work
                but use a lot of memories. and seems it has performance issue. */
//            imageView.image = UIImage.gifImage(self._gifData)

            /** 4. use same image array as imageView's animationImages.
                this kind works, but have different api than just set image.
                and when click on cell, the animation stops.    */
//            imageView.image = self._gifImageArray[0]
//            imageView.animationImages = self._gifImageArray
//            imageView.startAnimating()
        }

        return cell
    }
}

Notice in the cellForRowAtIndexPath: method, I tried different way to set imageView.

when I po object in lldb, I notice the animated imageView have a CAKeyframeAnimation. does this makes a tip?

How can I make the gif shown perfectly? Any suggestion would be helpful.

Here is a preview: after scroll, gif disappear, and reappear when touch

enter image description here


Solution

  • After I tried many times, I have finally figured out that I need to change:

    imageView.image = self._gifImage
    

    to:

    imageView.image = nil // this is the magical!
    imageView.image = self._gifImage
    

    just set image to nil before set to new image, and the animation work!! It's just like a magical!

    This is definitely apple's bug.