2017-10-17 210 views
0

在我的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 }()'然後再看一遍。 –

回答

3

您的代碼有幾個問題。最大的一點是您已將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://stackoverflow.com/q/5150186/)[2](https://stackoverflow.com/q/24728326/)所以我認爲這實際上是一個非常合理的提示。 –