DispatchQueue.main.async 阻塞主线程

Posted

技术标签:

【中文标题】DispatchQueue.main.async 阻塞主线程【英文标题】:DispatchQueue.main.async blocking the main thread 【发布时间】:2018-11-03 04:32:56 【问题描述】:

我一直在尝试在 Swift 3.0 中创建照片库,并且我想将存储在文档目录中的图像异步加载到集合视图中。我试过DispatchQueue.main.async,但它阻塞了主线程并冻结了应用程序几秒钟:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let identifier = "ImageCell"
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! ImageCell
    let url = self.imageURL[indexPath.row]
    cell.lazyLoadImage(from: url)
    return cell

还有 ImageCell 类:

class ImageCell: UICollectionViewCell 
    @IBOutlet weak var imageView: UIImageView!

    func lazyLoadImage(from url: URL) 
        DispatchQueue.main.async 
            if let image = UIImage(contentsOfFile: url.path) 
                self.imageView.image = image
            
        
    

感谢您的帮助。谢谢。

【问题讨论】:

如果您在应用程序冻结时暂停应用程序,主线程的回溯中是什么? 其实你什么都没做我的意思是你在主线程中,并且在主线程中调度块 如果图像只是文件,我不会认为您需要异步发送任何东西;只需加载图像。如果您的图像文件非常大,请考虑在单元格中加载更快的缩略图。 【参考方案1】:

先切换到后台线程加载图片,再切换到主线程显示图片。

func lazyLoadImage(from url: URL) 
     DispatchQueue.global(qos: .userInteractive).async 
         if let image = UIImage(contentsOfFile: url.path) 
             DispatchQueue.main.async 
                 self.imageView.image = image
             
         
    

【讨论】:

你还需要取消之前的任务(如果正在运行)【参考方案2】:

你做错了。简而言之,我可以说这不是“延迟加载”。您正在做的是阻止线程从URL 下载内容并将其加载到UIImageView。在下载发生并且您在“可重用单元”中使用它之前,该线程不会被释放,很明显您的应用程序会卡住!

解决方案

有许多最受欢迎的库,例如 AlamofireImage、SDWebImage、Kingfisher。我从中获取“SDWebImage”,您可以通过以下代码以async 方式调用加载图像:

imageView.sd_setImage(with: url , placeholderImage: nil)

另外,请参阅此 SO 问题 (how to implement lazy loading of images in table view using swift) 了解更多详情。

【讨论】:

以上是关于DispatchQueue.main.async 阻塞主线程的主要内容,如果未能解决你的问题,请参考以下文章

为啥 DispatchQueue.main.async 会影响单元格自动调整大小?

SwiftUI - HealthKit 中的 DispatchQueue.main.async

SwiftUI - HealthKit 中的 DispatchQueue.main.async

Swift 5:我无法让我的 UITableView 及时更新(同时使用 `DispatchQueue.global().sync` 和 `DispatchQueue.main.async`

在 DispatchQueue.main.async 上运行代码是不是更慢?

DispatchQueue.main.async 的初学者问题