代码之家  ›  专栏  ›  技术社区  ›  slider

从磁盘块主线程加载多个UIImage

  •  -1
  • slider  · 技术社区  · 7 年前

    我有一群当地人 UIImage 当它们各自的单元格被点击时,我需要以连续的顺序加载和呈现。例如,我有20个热狗图像,它们组合在一起形成动画。当用户轻触热狗电池时 UIImageView 应设置图像的动画。

    我知道如何使用 UIImageView animationImages 实现动画。我的问题是,从磁盘检索所有这些图像需要大约1.5秒,并且会阻塞主线程。

    我可以在 application(_:didFinishLaunchingWithOptions:) 它将这些图像从磁盘加载到后台线程中,以便在需要时将其存储在内存中,但这似乎有点黑客行为。

    有没有更好的方法可以快速从磁盘加载许多图像?


    编辑:这些图像是插图,因此是。png。

    Edit2:假设每个图像序列的总和为1 MB。我测试的图像尺寸比 UIImageView 's@3x要求。我 等待确认最终结果 UIImageView 在从我们的设计师那里获得正确的图像集之前,请先调整大小,因此使用适当大小的资产应该可以显著缩短时间,但我也在物理iPhone X上进行测试。

    class ViewModel {
    
        func getImages() -> [UIImage] {
    
            var images: [UIImage] = []
    
            for i in 0..<44 {
                if let image = UIImage(named: "hotDog\(i).png") {
                    images.append(image)
                }
            }
    
            return images
    
        }
    }
    
    class ViewController: UIViewController {
    
        private var viewModel: ViewModel!
    
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
            let cell = tableView.cellForRow(at: indexPath) as! CustomCell
            let images = viewModel.getImages()
            cell.animateImageView(withImages: images)
    
        }
    }
    
    class CustomCell: UITableViewCell {
    
        @IBOutlet weak var imageView: UIImageView!
    
        func animateImageView(withImages images: [UIImage]) {
    
            imageView.image = images.last
            imageView.animationImages = images
            imageView.animationDuration = TimeInterval(images.count / 20)
            imageView.animationRepeatCount = 1
            imageView.startAnimating()
    
        }
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Rob Md Fahim Faez Abir    7 年前

    我建议你试试 UIImage(contentsOfFile:) 而不是 UIImage(named:) 。在我的快速测试中,发现速度快了一个数量级以上。这在某种程度上是可以理解的,因为它做了很多事情(搜索资产、缓存资产等)。

    // slow
    
    @IBAction func didTapNamed(_ sender: Any) {
        let start = CFAbsoluteTimeGetCurrent()
        imageView.animationImages = (0 ..< 20).map {
            UIImage(named: filename(for: $0))!
        }
        imageView.animationDuration = 1.0
        imageView.animationRepeatCount = 1
        imageView.startAnimating()
    
        print(CFAbsoluteTimeGetCurrent() - start)
    }
    
    // faster
    
    @IBAction func didTapBundle(_ sender: Any) {
        let start = CFAbsoluteTimeGetCurrent()
        let url = Bundle.main.resourceURL!
        imageView.animationImages = (0 ..< 20).map {
            UIImage(contentsOfFile: url.appendingPathComponent(filename(for: $0)).path)!
        }
        imageView.animationDuration = 1.0
        imageView.animationRepeatCount = 1
        imageView.startAnimating()
    
        print(CFAbsoluteTimeGetCurrent() - start)
    }
    

    注意,这假定您在资源目录中有这些文件,您可能需要根据它们在项目中的位置进行相应的修改。还请注意,我避免这样做 Bundle.main.url(forResource:withExtension:) 在循环中,因为即使这样也会对性能产生明显的影响。