2015-07-07 46 views
6

Ho un codice pesante che viene eseguito per circa 0,2 secondi.Indicatore attività non visualizzato

Ho impostato l'indicatore di attività come questo; tuttavia, non viene visualizzato, ma piuttosto l'intero schermo si blocca per circa 0,2 secondi fino al termine del codice.

func heavyWork() { 
    self.actvityIndicator.startAnimating() 

    ... 
    // heavy loop codes here 
    ... 

    self.activityIndicator.stopAnimating() 
} 

È questo il modo corretto di utilizzare l'indicatore di attività?

Quando io commento

// self.activityIndicator.stopAnimating() 

l'indicatore di attività si presenta e vi rimane - i codici sono impostati a destra.

Ma l'interfaccia utente non sembra essere aggiornata al momento giusto.

Come ho detto, lo schermo si blocca solo senza mostrare l'indicatore di attività fino a quando non viene eseguito il codice pesante.

+2

è la vostra 'anello Codice delle pesanti in esecuzione su un thread in background? Il codice del ciclo pesante bloccherà l'interfaccia utente dalla visualizzazione dell'indicatore di attività. Inoltre, se si chiama 'heavyWork' su un thread in background, l'interfaccia utente non dovrebbe aggiornarsi poiché non si trova sul thread principale. – sbarow

+0

se sei su un thread in background, non puoi modificare nulla sull'interfaccia utente; se sei sul thread principale, allora non è il massimo per fare il lavoro pesante. – holex

risposta

14

Forse si vuole portare avanti con tale modello, invece:

func heavyWork() { 
    self.actvityIndicator.startAnimating() 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {() -> Void in 

     // ... 
     // heavy loop codes here 
     // ... 

     dispatch_async(dispatch_get_main_queue(), {() -> Void in 
      self.activityIndicator.stopAnimating() 
     }) 
    }); 
} 

come il lavoro pesante dovrebbe accadere in un sfondo filo ed è necessario aggiornare l'interfaccia utente su un principale filo dopo.


NOTA: ovviamente si presume si chiama ilfunc heavyWork()su un thread principale; in caso contrario, potrebbe essere necessario distrarre anche gli aggiornamenti iniziali dell'interfaccia utente al thread principale.

1

Ciò accade perché si sta eseguendo il codice di lavoro pesante sul thread principale. In questo modo il sistema non ha mai la possibilità di eseguire il commit della transazione grafica fino al termine della pesante routine. Il tuo metodo di avvio e arresto vengono impegnati contemporaneamente.
Per evitare che si debba eseguire il metodo di lavoro pesante su un altro dispatch_queue, ma si tenga presente che la maggior parte degli oggetti UIKit non sono thread-safe e devono essere nuovamente inviati sulla coda principale.

4

Se si desidera che l'applicazione sia reattiva mentre si esegue un task pesante, è necessario eseguirlo su un thread in background.

Questo è più o meno quello che sta succedendo qui: il thread principale della tua app viene eseguito in un ciclo di esecuzione. All'inizio di ogni iterazione del ciclo, l'iOS verifica la presenza di eventi (come l'interazione dell'utente, la modifica delle visualizzazioni dovuta all'animazione, i timer che vengono generati, ecc.) Quindi mette in coda un mucchio di metodi da eseguire. iOS quindi esegue ed esegue ciascuno di questi metodi e quindi, una volta completato, aggiorna il display. Quindi inizia l'iterazione del ciclo di esecuzione successiva. L'aggiornamento del display è costoso, quindi iOS non può farlo dopo l'esecuzione di ogni riga di codice.

Quindi, con il codice, quando si dice ad activityIndicator di avviareAnimating, indica a iOS che alla fine di ogni ciclo di esecuzione iterazione è necessario aggiornare l'immagine dell'indicatore di attività all'immagine successiva nella sequenza di animazione. Quindi, prima che iOS raggiunga la fine dell'iterazione del ciclo di esecuzione corrente, stai chiamando stopAnimating che indica a iOS che non è più necessario aggiornare le immagini. Quindi in pratica stai dicendo che si fermerà prima ancora che inizi.

È possibile utilizzare Grand Central Dispatch per eseguire facilmente il codice su un thread diverso.È importante notare, tuttavia, che qualsiasi aggiornamento all'interfaccia utente deve essere effettuato su thread.

func heavyWork() { 
    self.activityIndicator.startAnimating() 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 


     // Do heavy work here 


     dispatch_async(dispatch_get_main_queue()) { 
      // UI updates must be on main thread 
      self.activityIndicator.stopAnimating() 
     } 
    } 
} 

noti inoltre nel programmare in modo asincrono, come nell'esempio precedente, non è possibile restituire un valore dalla sezione asincrono nel metodo che invocato. Per esempio. nell'esempio precedente, non è possibile restituire un risultato del lavoro pesante dal metodo heavyWork(). Questo perché la funzione pianifica il codice asincrono da eseguire su un thread diverso, quindi restituisce immediatamente in modo che possa continuare con l'iterazione del ciclo di esecuzione corrente.

1

SWIFT 4:

func heavyWork() { 
    self.actvityIndicator.startAnimating() 

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

     // ... 
     // heavy loop codes here 
     // ... 

     DispatchQueue.main.async { 
      self.actvityIndicator.stopAnimating() 
     } 
    } 
}