2017-07-15 1 views
1

ist der Code von meinem Haupt-ViewcontrollerWie führe ich eine Aufgabe in einer anderen Funktion aus und aktualisiere die Benutzeroberfläche von dort aus, während die Aufgabe fortschreitet? Dieser

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 
    } 


} 

Das ist mein Tweak-Klasse, wo die Symbole heruntergeladen werden, wenn Sie eine Instanz davon erstellen

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!)! 

    } 
} 

ich die UIProgressView (progressUI aktualisieren möchten) wie jede Tweak-Instanz gemacht wird. Die Benutzeroberfläche wird jedoch erst aktualisiert, nachdem die Funktion zurückgegeben wurde. Kann mir jemand erklären, was alles funktioniert und wie Threading durchgeführt werden sollte? Ich bin neu in der schnellen und asynchronen Programmierung.

Antwort

1

Ihre for-Schleife befindet sich bereits im Hauptthread. Daher werden alle UI-Aktualisierungen blockiert, wodurch nicht nur Fortschrittsbalkenaktualisierungen, sondern auch Benutzerinteraktionen deaktiviert werden.

Jede lange laufende Aufgabe sollte im Hintergrund-Thread ausgeführt werden. Zum Glück ist das in Swift einfach.

Da Sie bereits Fortschritte Ansicht zu aktualisieren sind, so etwas wie dies funktionieren würde:

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

statt nur simulateDownload in viewDidLoad

Aufruf Bitte beachten Sie, dass mit diesem Ansatz, Sie nicht die Rückkehr verwenden können Wert von der Funktion direkt aus dem Haupt-Thread.

Was sollten Sie stattdessen tun ist, um den Wert aus einem Verschluss bietet, etwa so:

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

und es verwenden, dies wie:

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

Dies ist nur an der Oberfläche gekratzt, wenn Sie Möchten Sie mehr über Verschlüsse in Swift erfahren, empfehle ich Ihnen, dies zu lesen: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID94

+1

Vielen Dank. Es funktionierte. Wie kann ich feststellen, ob ein Block im Haupt-Thread ist oder nicht? Und 'DispatchQueue.global (qos: .background) .async {}' macht, was in dem Block gegeben in einem anderen Thread ausgeführt wird? –

+0

Um zu überprüfen, ob Sie im Haupt-Thread sind, überprüfen Sie einfach 'Thread.isMainThread', und ja, der Block läuft in einem anderen Thread. – Dule

Verwandte Themen