2014-11-04 12 views
9

Nel mio codice ho un ciclo for semplice che esegue il ciclo 100 volte con cicli nidificati per creare un ritardo. Dopo il ritardo, sto aggiornando un elemento della vista di avanzamento nell'interfaccia utente attraverso un dispatch_async. Tuttavia, non riesco a far aggiornare l'interfaccia utente. Qualcuno sa perché l'interfaccia utente non si sta aggiornando? Nota: l'istruzione di stampa di seguito viene utilizzata per verificare che il ciclo for sia in loop correttamente.Aggiornamento dell'interfaccia utente utilizzando Dispatch_Async in Swift

for i in 0..<100 { 

    //Used to create a delay 
    for var x = 0; x<100000; x++ { 
     for var z = 0; z<1000; z++ { 

     } 
    } 

    println(i) 

    dispatch_async(dispatch_get_main_queue()) { 
     // update some UI 
     self.progressView.setProgress(Float(i), animated: true) 

    } 
    } 
+0

Puoi confermare che la chiamata setProgress sta sparando? Prova a lanciare qualche accesso o un punto di interruzione della registrazione. Inoltre è generalmente preferibile usare NSOperation per le cose che usano Cocoa. – macshome

+0

Interessante, ho buttato un po 'di accesso e sembra che la chiamata setProgress non stia sparando. Perché dovrebbe essere? – dslkfjsdlfjl

+0

Bene, quando si invia dispatch_async dipende dal sistema quando deve sparare. Se è necessario aggiornare l'interfaccia in modo tempestivo, non utilizzare async. In Xcode puoi mettere in pausa l'app e dare un'occhiata anche ai blocchi in sospeso. – macshome

risposta

33

Tre osservazioni, due di base, uno un po 'più avanzato:

  1. Il tuo ciclo non sarà in grado di aggiornare l'interfaccia utente in quel thread principale a meno che il circuito stesso è in esecuzione su un altro thread. Quindi, puoi inviarlo a qualche coda in background. In Swift 3:

    DispatchQueue.global(qos: .utility).async { 
        for i in 0 ..< kNumberOfIterations { 
    
         // do something time consuming here 
    
         DispatchQueue.main.async { 
          // now update UI on main thread 
          self.progressView.setProgress(Float(i)/Float(kNumberOfIterations), animated: true) 
         } 
        } 
    } 
    

    a Swift 2:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
        for i in 0 ..< kNumberOfIterations { 
    
         // do something time consuming here 
    
         dispatch_async(dispatch_get_main_queue()) { 
          // now update UI on main thread 
          self.progressView.setProgress(Float(i)/Float(kNumberOfIterations), animated: true) 
         } 
        } 
    } 
    
  2. noti inoltre che il progresso è un numero da 0.0 a 1.0, quindi è presumibilmente desidera dividere per il numero massimo di iterazioni per la ciclo continuo.

  3. Se gli aggiornamenti dell'interfaccia utente derivano più rapidamente dal thread in background di quello in cui l'interfaccia utente è in grado di gestirli, il thread principale può essere retrocesso con le richieste di aggiornamento (facendolo sembrare molto più lento di quello che è realmente). Per risolvere questo problema, si potrebbe prendere in considerazione l'utilizzo dell'origine di invio per disaccoppiare l'attività di "aggiornamento dell'interfaccia utente" dall'effettivo processo di aggiornamento in background.

    Si può usare un DispatchSourceUserDataAdd (a Swift 2, è un dispatch_source_t di DISPATCH_SOURCE_TYPE_DATA_ADD), inviare add chiamate (dispatch_source_merge_data a Swift 2) dal thread in background con la frequenza desiderata, e l'interfaccia utente li elaborerà così rapidamente come è possibile ma li unirà insieme quando chiama data (dispatch_source_get_data in Swift 2) se gli aggiornamenti in background arrivano più rapidamente di quanto l'UI possa altrimenti elaborarli. Ciò consente di ottenere le massime prestazioni in background con aggiornamenti UI ottimali, ma soprattutto, ciò garantisce che l'UI non diventi un collo di bottiglia.

    Quindi, prima di dichiarare una variabile per tenere traccia dei progressi:

    var progressCounter: UInt = 0 
    

    E ora il ciclo in grado di creare una fonte, definire che cosa fare quando la sorgente viene aggiornato, e quindi lanciare il ciclo asincrono che aggiorna la fonte. In Swift 3 cioè:

    progressCounter = 0 
    
    // create dispatch source that will handle events on main queue 
    
    let source = DispatchSource.makeUserDataAddSource(queue: .main) 
    
    // tell it what to do when source events take place 
    
    source.setEventHandler() { [unowned self] in 
        self.progressCounter += source.data 
    
        self.progressView.setProgress(Float(self.progressCounter)/Float(kNumberOfIterations), animated: true) 
    } 
    
    // start the source 
    
    source.resume() 
    
    // now start loop in the background 
    
    DispatchQueue.global(qos: .utility).async { 
        for i in 0 ..< kNumberOfIterations { 
         // do something time consuming here 
    
         // now update the dispatch source 
    
         source.add(data: 1) 
        } 
    } 
    

    a Swift 2:

    progressCounter = 0 
    
    // create dispatch source that will handle events on main queue 
    
    let source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue()); 
    
    // tell it what to do when source events take place 
    
    dispatch_source_set_event_handler(source) { [unowned self] in 
        self.progressCounter += dispatch_source_get_data(source) 
    
        self.progressView.setProgress(Float(self.progressCounter)/Float(kNumberOfIterations), animated: true) 
    } 
    
    // start the source 
    
    dispatch_resume(source) 
    
    // now start loop in the background 
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
        for i in 0 ..< kNumberOfIterations { 
    
         // do something time consuming here 
    
         // now update the dispatch source 
    
         dispatch_source_merge_data(source, 1); 
        } 
    } 
    
+0

Grazie mille!Molto istruttivo e fa esattamente quello che dovevo fare! – dslkfjsdlfjl

Problemi correlati