Swift 从磁盘块主线程加载多个UIImage
我有一组本地Swift 从磁盘块主线程加载多个UIImage,swift,uiimageview,uiimage,uikit,Swift,Uiimageview,Uiimage,Uikit,我有一组本地UIImages,当点击它们各自的单元格时,我需要按顺序加载和显示它们。例如,我有20个热狗的图像,它们组合在一起形成动画。当用户轻触热狗单元格时,单元格的UIImageView应设置图像动画 我知道如何使用UIImageView的animationImages来实现动画。我的问题是,从磁盘检索所有这些映像需要约1.5秒,并且会阻塞主线程 我可以在应用程序中实例化一个helper类(uquot:didfishlaunchingwithoptions:),该类可以在后台线程上从磁盘加载
UIImage
s,当点击它们各自的单元格时,我需要按顺序加载和显示它们。例如,我有20个热狗的图像,它们组合在一起形成动画。当用户轻触热狗单元格时,单元格的UIImageView
应设置图像动画
我知道如何使用
UIImageView
的animationImages
来实现动画。我的问题是,从磁盘检索所有这些映像需要约1.5秒,并且会阻塞主线程
我可以在应用程序中实例化一个helper类(uquot:didfishlaunchingwithoptions:)
,该类可以在后台线程上从磁盘加载这些图像,以便在需要时将它们保存在内存中,但这似乎有点不太妥当
有没有更好的方法可以快速从磁盘加载许多映像
编辑:这些图像是插图,因此是.png Edit2:假设每个图像序列的总和为1MB。我测试的图像尺寸比
UIImageView
的@3x要求大33-60%。我正在等待确认最终的UIImageView
大小,然后再从我们的设计师那里获得正确的图像集,因此使用适当大小的资产应该可以大大缩短时间,但我也在物理iphonex上进行测试
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()
}
}
类视图模型{
func getImages()->[UIImage]{
变量图像:[UIImage]=[]
对于0中的i..我建议您尝试UIImage(contentsOfFile:)
而不是UIImage(name:)
。在我的快速测试中,我发现它的速度快了一个数量级以上。这在某种程度上是可以理解的,因为它做了很多事情(搜索资产、缓存资产等)
//慢
@iAction func didTapNamed(u发送方:任意){
let start=CFAbsoluteTimeGetCurrent()
imageView.animationImages=(0..<20).map{
UIImage(名称:filename(用于:$0))!
}
imageView.animationDuration=1.0
imageView.animationRepeatCount=1
imageView.startAnimating()
打印(CFAbsoluteTimeGetCurrent()-start)
}
//更快
@iAction func didTapBundle(u发送方:任意){
let start=CFAbsoluteTimeGetCurrent()
让url=Bundle.main.resourceURL!
imageView.animationImages=(0..<20).map{
UIImage(contentsOfFile:url.appendingPathComponent(文件名:$0)).path)!
}
imageView.animationDuration=1.0
imageView.animationRepeatCount=1
imageView.startAnimating()
打印(CFAbsoluteTimeGetCurrent()-start)
}
注意,这假定您在资源目录中有文件,并且您可能必须根据它们在项目中的位置相应地修改它。还要注意,我避免在循环中执行Bundle.main.url(forResource:withExtension:)
,因为即使这样也会对性能产生明显的影响“我的问题是,从磁盘检索所有这些映像需要约1.5秒,并且会阻塞主线程"与图像视图的大小相比,这些图像是否有不必要的巨大?我也很好奇为什么加载这些图像需要这么长时间。我觉得问题更像是您正在将它们加载到背景线程中。我建议使用仪器来查看真正花时间的内容。此外,您还没有展示您的行为ual代码使得无法以任何明确的方式提供帮助…预加载图像可以解决此问题(虽然您不必返回到didfishlaunchwithoptions
;为什么不在加载视图时触发此操作;这感觉像是视图或视图控制器的责任,而不是应用程序代理)。但是如果它们需要1.5秒,它们一定很大和/或很多,我也会非常担心内存使用的峰值。延迟可能只是几个问题之一。@matt See Edit2…@Rob preload听起来可行,但我有太多具有独特图像集的单元格来加载它们。很好的解决方案。对我来说大约快11.7倍1.谢谢你,罗伯。
// 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)
}