2017-07-15 38 views
1

這是從我的主視圖控制器代碼如何在另一個功能中執行任務並隨着任務的進展更新UI?

import UIKit 

class ViewController: UIViewController 
{ 

    @IBOutlet weak var progressUI: UIProgressView! 
    override func viewDidLoad() 
    { 
     super.viewDidLoad() 
     simulateDownload() 
    } 



    override func didReceiveMemoryWarning() 
    { 
     super.didReceiveMemoryWarning() 

    } 

    func simulateDownload() -> Array<Tweak> 
    { 
     var results = [Tweak]() 
     let searchQuery = "activator" 
     let url = URL(string: "https://cydia.saurik.com/api/macciti?query=" + searchQuery) 
     let urlData = try? Data(contentsOf: url!) 
     var i = 0 
     let jsonResult = try? JSONSerialization.jsonObject(with: urlData!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: Any] 
     let resultTweaks = jsonResult?["results"] as! Array<Any> 
     for tweak in resultTweaks 
     { 
      i += 1 
      let progress = (Float(i)/Float(resultTweaks.count)) 
      results.append(Tweak(tweakdata: tweak as! [String: String])) 
      DispatchQueue.main.async() 
      { 
       self.progressUI.progress = progress 

      } 
      print(progress) 

     } 
     print("done") 
     return results 
    } 


} 

這是我的好辦法類,就是當你創建

import Foundation 
import UIKit 

class Tweak 
{ 
    var name, id, section, description, version, thumbURL: String 
    var icon: UIImage 
    init(tweakdata: Dictionary<String, Any>) 
    { 
     self.name = tweakdata["display"] as! String 
     self.id = tweakdata["name"] as! String 
     self.section = tweakdata["section"] as! String 
     self.description = tweakdata["summary"] as! String 
     self.version = tweakdata["version"] as! String 
     self.thumbURL = "https://cydia.saurik.com/[email protected]/" + self.id + ".png" 
     //load icon 
     let imgURL = URL(string: self.thumbURL) 
     let imgData = try? Data(contentsOf: imgURL!) 
     self.icon = UIImage(data: imgData!)! 

    } 
} 

我想更新UIProgressView它的實例圖標下載(progressUI ),因爲每個Tweak實例都被製作出來。但是UI只會在函數返回後更新。有人能解釋我所有這些工作以及應該如何進行線程化? 我是新來的快速和異步編程。

回答

1

您的for循環已經在主線程中,因此它將阻止任何UI更新,這不僅會禁用進度欄更新,還會禁止用戶交互。

任何長時間運行的任務應該在後臺線程上運行。幸運的是,這在Swift中很容易。

既然你已經更新進度來看,像這樣的工作:

DispatchQueue.global(qos: .background).async { 
    simulateDownload() 
} 

,而不是隻在viewDidLoad

調用simulateDownload請注意,使用這種方法,你不能使用回直接來自主線程的函數的值。

你應該做的,而不是從一個封閉提供的價值,是這樣的:

func simulateDownload(@escaping closure: (_ result:Array<Tweak>) ->()) { 
    DispatchQueue.global(qos: .background).async { 
     [...] 
     DispatchQueue.main.async{ 
      closure(results) 
     } 
    } 
} 

,並使用它像這樣:

simulateDownload(closure: { 
    results in 
    [...] 
}) 

這只是表面文章,如果您想要了解更多關於Swift中的閉包的信息,我建議您閱讀下面的內容:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID94

+1

非常感謝。有效。 如何確定塊是否在主線程中? 而且'DispatchQueue.global(qos:.background).async {}'會在不同的線程中運行塊中給出的任何東西? –

+0

要檢查你是否在主線程中,只需檢查'Thread.isMainThread',並且是,該塊運行在不同的線程中。 – Dule

相關問題