52

Stavo riscontrando problemi nella modifica di una vista all'interno di un thread. Ho provato ad aggiungere una sottoview ma ci sono voluti circa 6 o più secondi da visualizzare. Finalmente ho funzionato, ma non so esattamente come. Quindi mi chiedevo perché ha funzionato e che cosa è la differenza tra i seguenti metodi:Qual è la differenza tra performSelectorOnMainThread e dispatch_async sulla coda principale?

//this worked -added the view instantly 
dispatch_async(dispatch_get_main_queue(), ^{ 
    //some UI methods ej 
    [view addSubview: otherView]; 
} 

//this took around 6 or more seconds to display 
[viewController performSelectorOnMainThread:@selector(methodThatAddsSubview:) withObject:otherView 
waitUntilDone:NO]; 

//Also didnt work: NSNotification methods - took also around 6 seconds to display 
//the observer was in the viewController I wanted to modify 
//paired to a method to add a subview. 
[[NSNotificationCenter defaultCenter] postNotificationName: 
@"notification-identifier" object:object]; 

Per riferimento questo sono stati chiamati all'interno di questo completetion Handler della classe del ACAccountStore.

accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) { 
      if(granted) { 
      //my methods were here 
      } 
} 

Edit: Quando dico che non ha funzionato volevo dire ci sono voluti circa 6 secondi per visualizzare la vista ho aggiunto.

+0

Quando dici che 'performSelectorOnMainThread:' non ha funzionato, come ha funzionato? Hai ricevuto un messaggio di errore? È stato un errore di runtime un errore di compilazione? Se non hai ricevuto un errore, come sai che è fallito? –

+0

È 'addSubview:' l'unico metodo che hai usato che ha toccato gli elementi dell'interfaccia utente, o ci sono anche altri? –

+0

@AndrewMadsen Ho dimenticato di dire che ha funzionato ma ci sono voluti circa 6 o più secondi da visualizzare. –

risposta

69

Per impostazione predefinita, -performSelectorOnMainThread:withObject:waitUntilDone: pianifica solo il selettore da eseguire nella modalità ciclo di esecuzione predefinita. Se il ciclo di esecuzione è in un'altra modalità (ad esempio la modalità di tracciamento), non verrà eseguito fino a quando il ciclo di esecuzione non tornerà alla modalità predefinita. Puoi aggirare questo con la variante -performSelectorOnMainThread:withObject:waitUntilDone:modes: (passando tutte le modalità in cui vuoi che venga eseguito).

D'altra parte, dispatch_async(dispatch_get_main_queue(), ^{ ... }) eseguirà il blocco non appena il ciclo di esecuzione principale restituirà il flusso di controllo al ciclo di eventi. Non si preoccupa delle modalità. Quindi, se non vuoi preoccuparti delle modalità, dispatch_async() potrebbe essere la soluzione migliore.

+1

Quali sono le modalità e quando dovrei preoccuparmi di loro? – ma11hew28

+2

@MattDiPasquale: su iOS, puoi fondamentalmente ignorarli, in genere il runloop viene eseguito nella modalità predefinita. Su OS X ci sono altre 3 modalità che puoi vedere, 'NSConnectionReplyMode',' NSModalPanelRunLoopMode' e 'NSEventTrackingRunLoopMode'. Puoi cercare i documenti per quelli che ti interessano. –

+2

Si noti che in iOS UITrackingRunLoopMode viene utilizzato per determinati tracciamenti di eventi tattili (quando un UIScrollView traccia un movimento tattile). – cdemiris99

0

Avete provato il PerformSelectorOnMainThread con waitUntilDone=YES

Esempio:

Codice:

[viewController performSelectorOnMainThread:@selector(methodThatAddsSubview:) withObject:otherView waitUntilDone:YES]; 

penso che potrebbe risolvere il problema come del perché l'PerformSelectorOnMainThread vuole tanto tempo per rispondere.

1

È probabile perché performSelectorOnMainThread:withObject:waitUntilDone: accoda il messaggio con le modalità di ciclo di esecuzione comuni. In base a Apple's Concurrency Programming Guide, la coda principale interconnette le attività in coda con altri eventi dal ciclo di esecuzione dell'app. Pertanto, se ci sono altri eventi da elaborare nella coda degli eventi, i blocchi in coda nella coda di invio possono essere eseguiti per primi, anche se sono stati inviati in seguito.

This article è una spiegazione eccellente per performSelectorOnMainThread rispetto a dispatch_async, che risponde anche alla domanda precedente.

Problemi correlati