【问题标题】:How to fix UIActivityIndicatorView from startAnimation again in an UIImageView Extension used in a TableView如何在 TableView 中使用的 UIImageView 扩展中再次从 startAnimation 修复 UIActivityIndi​​catorView
【发布时间】:2019-05-13 14:28:08
【问题描述】:

我有一个UIImageView 扩展,其中包含一个下载设置图像的方法,该扩展还包含一个UIActivityIndicatorView,我在加载图像之前将其设置为一个视图,一旦加载图像,我将删除或隐藏@987654323 @来自UIImageView

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 时,它开始在UIImageView 上再次为indicator 设置动画。 我该如何防止这种情况发生?

【问题讨论】:

    标签: ios swift nsoperationqueue nsoperation uiactivityindicatorview


    【解决方案1】:

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

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

    【讨论】:

    • 您还需要哪些信息,提供的代码还不够吗?因为我没有在包含 tableview 的 ViewController 中做任何特别的事情。
    • 两个问题: 1. 你是为每张图片设置一个活动指示器,还是只是一个通用的? 2.最后一段代码是完整的cellForRow函数吗?
    • 您提供的链接包含如何缓存下载的图像,已在operatorManager.loadImage 中处理,该函数在setImage 函数中调用,在UIImageView 扩展中提供。如果您仔细查看我发布的扩展程序,UIActivityIndicatorView 是在我即将下载图像时创建和使用的,当completionHandler 返回图像时它会隐藏自身。最后2段代码是cellForRow的完整代码
    • 那么问题可能出在loadImage。如果可以,请发布。
    • loadImage的问题吗?
    【解决方案2】:

    解决方案对我来说很简单,直到我尝试了它。它不是最好的,但它解决了我的问题。

        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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多