斯威夫特UIActivityView stopAnimating()不工作

斯威夫特UIActivityView stopAnimating()不工作

问题描述:

在我的UIImageView子类中,我有一个UIActivityIndicatorView和功能,以下载定义为这样的图像:斯威夫特UIActivityView stopAnimating()不工作

class FooUIImageView: UIImageView { 

     var activityIndicator: UIActivityIndicatorView { 
      let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white) 
      activityIndicator.hidesWhenStopped = true 
      activityIndicator.center = CGPoint(x: self.frame.width/2, y: self.frame.height/2) 
      self.addSubview(activityIndicator) 
      return activityIndicator 
     } 

     func downloadImageFrom(url: URL, imageMode: UIViewContentMode) { 

      self.activityIndicator.startAnimating() 
      self.activityIndicator.stopAnimating() 

      contentMode = imageMode 
      if let cachedImage = imageCache.object(forKey: url.absoluteString as NSString) as? UIImage { 
       self.image = cachedImage 
      } else { 
       URLSession.shared.dataTask(with: url) { data, _, error in 
        guard let data = data, error == nil else { return } 
         DispatchQueue.main.async { 
          if let imageToCache = UIImage(data: data) { 
           self.activityIndicator.stopAnimating() 
           self.imageCache.setObject(imageToCache, forKey: url.absoluteString as NSString) 
           self.image = imageToCache 
          } else { 
           self.activityIndicator.stopAnimating() 
           self.image = nil 
          } 
         } 
       }.resume() 
      } 

      activityIndicator.stopAnimating() 
     } 
} 

当运行我的应用程序,该activityIndicator启动加载 - 然后将图像最终显示。但是,activityIndicator仍然保持在屏幕上,并且不会消失。在我所称的stopAnimating()以上的地方,指标实际上都停止了动画。如果我在调用它之后立即停止它,但它仍然存在,这特别令人困惑。

+0

运行您的代码,等待图像加载,然后查看调试器中的视图层次结构。然后更改属性:'var activityIndi​​cator:UIActivityIndi​​catorView = { // Same body }()'然后再看一遍。 –

您的代码有几个问题。最大的一点是您已将activityIndi​​cator作为计算属性。每次你引用它时,你的闭包代码都会被执行,你会得到一个新的,从未见过的活动指示器。试试这个代码作为一个测试:

print(String(format: "activityIndicator address = %X", activityIndicator)) 
print(String(format: "activityIndicator address = %X", activityIndicator)) 
print(String(format: "activityIndicator address = %X", activityIndicator)) 

请注意,你会得到不同的地址为每个打印语句。

这意味着每次您引用activityIndicatorself.activityIndicator时,您都会创建另一个活动指示符并将其添加到您的视图层次结构中。这不是你想要的。

相反,让你变懒VAR:

lazy var activityIndicator: UIActivityIndicatorView = { 
    let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white) 
    activityIndicator.hidesWhenStopped = true 
    activityIndicator.center = CGPoint(x: self.frame.width/2, y: self.frame.height/2) 
    self.addSubview(activityIndicator) 
    return activityIndicator 
}() 

注意代码是如何有赋值,而盖具有括号后记(())。

lazy限定符意味着该变量直到第一次被引用时才会被创建,然后只创建一次。

闭包后的元素意味着闭包被调用为函数,并且变量activityIndicator将包含闭包的结果。

您还应该在您的dataTask的完成处理程序中的任何地方摆脱电话的呼叫DispatchQueue.main.async。您只想在下载完成后停止动画,并且您必须在主线程中进行类似的UI调用。额外致电stopAnimating()只会导致您的问题。

+0

Aww,我想让他自己弄清楚多个实例。 :)(请注意,'lazy'不是必须的,这部分将在没有它的情况下解决,另外,你可以使它成为一个常量。) –

+0

对于开始的开发者来说,“在调试器中查看视图层次结构”并不意味着任何东西。微妙的提示往往会在新手上迷失方向。 –

+0

那么,*Google打击“在调试器中查看视图层次结构”是[Apple的调试指南](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/debugging_with_xcode/chapters/special_debugging_workflows的.html)。然后是Ray Wenderlich指南,随后是几个Stack Overflow问题,它们很好地解释了它。 [1](https://*.com/q/5150186/)[2](https://*.com/q/24728326/)所以我认为这实际上是一个非常合理的提示。 –