如何在 TableView 中使用的 UIImageView 扩展中再次从 startAnimation 修复 UIActivityIndi​​catorView

How to fix UIActivityIndicatorView from startAnimation again in an UIImageView Extension used in a TableView

我有一个 UIImageView 扩展,带有下载一组图像的方法,该扩展还包含一个 UIActivityIndicatorView,我在加载图像后将其设置为加载图像之前的视图从 UIImageView

中删除或隐藏 UIActivityIndicatorView
extension UIImageView {

    private static let imageProcessingQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".imageprocessing", attributes:  .concurrent)

    var activityIndicator: UIActivityIndicatorView! {
        get {
            return objc_getAssociatedObject(self, &activityIndicatorAssociationKey) as? UIActivityIndicatorView
        }
        set(newValue) {
            objc_setAssociatedObject(self, &activityIndicatorAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN)
        }
    }

    func showActivityIndicatory() {

        // activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
        activityIndicator = UIActivityIndicatorView(frame: CGRect.init(x: 0, y: 0, width: 50, height: 50))
        activityIndicator.center = self.center
        activityIndicator.hidesWhenStopped = true
        activityIndicator.style = UIActivityIndicatorView.Style.gray

        self.isUserInteractionEnabled = false

        UIImageView.imageProcessingQueue.async {
            DispatchQueue.main.async {
                self.activityIndicator.startAnimating()
                self.addSubview(self.activityIndicator)

             }
        }
    }

    func hideIndicator() {
        UIImageView.imageProcessingQueue.async {
            DispatchQueue.main.async {
                self.activityIndicator.stopAnimating()
                self.activityIndicator.removeFromSuperview()

            }
        }
    }

    func setImage(url : String)  {
        self.showActivityIndicatory()
        operatorManager.loadImage(url: url) { (image) in
            self.image = image
            self.hideIndicator()
        }
    }
}

然后我可以像这样使用这个扩展功能,

guard let cell = tableView.dequeueReusableCell(withIdentifier:"Tableview", for: indexPath) as? TableViewCell else {
    fatalError()
}

let imagees = list[indexPath.row]

cell.labelView.text = imagees.urlString
cell.iconView.setImage(url: imagees.urlString)

这是 Operation 用于从缓存(如果可用)或从服务器加载图像。

    class LoadImageOperation: ConcurrentOps<UIImage> {

private let session: URLSession
private let url: String
private var task: URLSessionTask?
private var defaultImage: UIImage?
// MARK: - Init

init(session: URLSession = URLSession.shared, url: String) {
    self.session = session
    self.url = url
    self.defaultImage = UIImage(named: "icons")
}


override func main() {

    guard let imageURL = URL(string: url) else {
        cancel()
        return
    }



    if let cachedImage = DataCache.shared.object(forKey: url) {

        DispatchQueue.main.async {
        self.complete(result: cachedImage as! UIImage)

        }
       cancel()
    }


    task = session.downloadTask(with: imageURL){ (url,response,error) in

        guard let url = url ,
            let data = try? Data(contentsOf: url),
            let image = UIImage(data: data) else {

                DispatchQueue.main.async {

                    if error != nil {
                        self.complete(result: self.defaultImage!)
                    } else {
                         self.complete(result: self.defaultImage!)
                    }
                }
                return
        }
        DispatchQueue.main.async {

            DataCache.shared.saveObject(object: image, forKey: self.url)
            self.complete(result: image)
        }

    }
    task?.resume()


}

}

操作在这里管理,

func loadImage(url: String, completionHandler: @escaping (_ result: UIImage) ->Void) {

    let operation = LoadImageOperation(url: url)

    operation.completionHandler = completionHandler
    operation.name = "loadImageOperation"
    queueManager.enqueue(operation)

}

当我的 tableView 第一次开始加载时,indicator 完美地显示和隐藏,但是当我滚动 tableview 时,它再次开始在 indicator 上设置动画 UIImageView。 我该如何防止这种情况?

显示 activity 指示器的原因是滚动时,单元格被重复使用(出于性能原因)以显示新数据。这意味着每次滚动到新单元格时,它都会加载并调用 cellForRow,同时调用加载 activity 指标的函数。

如果您需要一步一步的回答,您应该提供有关如何处理 UITableView 的更多信息,但我认为您可能希望实施图像缓存以避免每次加载单元格时都加载图像。查看 了解更多信息。

在我尝试之前,这个解决方案对我来说很简单 out.Its 不是最好的,但它解决了我的问题。

    func setImage(url : String)  { 
    if DataCache.shared.object(forKey: url) != nil {
              self.hideIndicator()
    }else{
        self.showActivityIndicatory()
    }
    operatorManager.loadImage(url: url) { (image) in
        self.image = image
        self.hideIndicator()
    }
}

我什至在 运行 我的 Operation 之前检查了图像是否被缓存,如果它被缓存,我隐藏 UIActivityIndicatorView 否则我显示它。我认为这不是 100% 的原因是,该操作还在检查我认为可以增加 CPU.

的缓存图像