2012-11-20 13 views
10

In relazione a this question Mi chiedevo se esiste una logica generalmente accettata in merito all'utilizzo di NSNotification, con un osservatore nel thread principale, rispetto all'utilizzo di GCD per inviare il lavoro da un thread in background al thread principale?NSNotification vs. dispatch_get_main_queue

Sembra che con una configurazione di notifica osservatore si deve ricordare di abbattere l'osservatore quando la visualizzazione scarica, ma poi si ignora in modo affidabile la notifica, in cui come l'invio di un lavoro per il filo conduttore può provocare un blocco in esecuzione quando la vista è stata scaricata.

Come tale, mi sembra che le notifiche dovrebbero fornire una migliore stabilità app. Suppongo che l'opzione di invio fornisca prestazioni migliori da quello che ho letto su GCD?

UPDATE:

Sono consapevole del fatto che le notifiche e la spedizione possono lavorare felicemente insieme e, in alcuni casi, dovrebbero essere utilizzati insieme. Sto cercando di scoprire se ci sono casi specifici in cui uno dovrebbe/non dovrebbe essere usato.

Un caso ad esempio: Perché dovrei scegliere il thread principale per sparare una notifica da un blocco spedito piuttosto che solo dispacciamento la funzione di ricezione sulla coda principale? (Ovviamente ci sarebbero alcune modifiche alla funzione di ricezione nei due casi, ma il risultato finale sembrerebbe essere lo stesso).

+2

Queste non sono opzioni che si escludono a vicenda. È possibile utilizzare GCD per lavorare su un thread in background, quindi tornare al thread principale e inviare una NSNotification (che viene ricevuta sullo stesso thread da cui viene inviata). O non capisco la domanda? – Kitsune

+0

@Kitsune Mi rendo conto che i due possono essere usati tranquillamente insieme, sono curioso di sapere se ci sono casi ben noti in cui l'uno o l'altro è sempre usato/evitato. Ho cercato esempi in cui GCD è costantemente utilizzato per inviare lavoro a un thread in background, ma a volte vengono utilizzate notifiche per tornare al thread principale e altre volte, GCD viene utilizzato per tornare al thread principale. – Endophage

+1

Sapete che le notifiche sono consegnate sullo stesso thread in cui sono state pubblicate? Quindi non possono essere utilizzati per "tornare al thread principale"! – Felix

risposta

14

Il NSNotificationCenter e gcd & dispatch_get_main_queue() servono a scopi molto diversi. Io non faccio "contro" è veramente applicabile.

NSNotificationCenter fornisce un modo di parti disparate de-accoppiamento della vostra applicazione. Ad esempio, lo kReachabilityChangedNotification nel codice di esempio Reachability di Apple viene registrato nel centro notifiche quando lo stato della rete del sistema cambia. E a sua volta puoi chiedere al centro notifiche di chiamare il tuo selettore/invocazione in modo da poter rispondere a tale evento. (Think Air Raid Siren)

gcd d'altra parte fornisce un modo rapido di assegnare il lavoro da fare su una coda specificata da te. Ti consente di dire al sistema i punti in cui il tuo codice può essere sezionato e elaborato separatamente per trarre vantaggio da thread multipli e da CPU multi-core.

generale (quasi sempre) le notifiche si osservano sul filo su cui sono stati scritti. Con l'eccezione di un pezzo di API ...

L'unico pezzo di API dove questi concetti intersecano è NSNotificationCenter 's:

addObserverForName:object:queue:usingBlock: 

Questo è essenzialmente un metodo conveniente per assicurare che una determinata notifica è osservato su un dato thread. Sebbene il parametro "usingBlock" dia via che dietro le quinte sta usando gcd.

Ecco un esempio del suo utilizzo. Supponiamo che da qualche parte nel mio codice compare un NSTimer di chiamare questo metodo ogni secondo:

-(void)timerTimedOut:(NSTimer *)timer{ 
    dispatch_async(dispatch_get_global_queue(0, 0), ^{ 
     // Ha! Gotcha this is on a background thread. 
     [[NSNotificationCenter defaultCenter] postNotificationName:backgroundColorIsGettingBoringNotification object:nil]; 
    }); 
} 

voglio usare il backgroundColorIsGettingBoringNotification come un segnale per me di cambiare il colore di sfondo della vista di mio controller della vista. Ma è pubblicato su un thread in background. Bene, posso usare la suddetta API per osservare che solo sul thread principale.Nota viewDidLoad nel codice seguente:

@implementation NoWayWillMyBackgroundBeBoringViewController { 
    id _observer; 
} 
-(void)observeHeyNotification:(NSNotification *)note{ 
    static NSArray *rainbow = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     rainbow = @[[UIColor redColor], [UIColor orangeColor], [UIColor yellowColor], [UIColor greenColor], [UIColor blueColor], [UIColor purpleColor]]; 
    }); 
    NSInteger colorIndex = [rainbow indexOfObject:self.view.backgroundColor]; 
    colorIndex++; 
    if (colorIndex == rainbow.count) colorIndex = 0; 
    self.view.backgroundColor = [rainbow objectAtIndex:colorIndex]; 
} 
- (void)viewDidLoad{ 
    [super viewDidLoad]; 
    self.view.backgroundColor = [UIColor redColor]; 
    __weak PNE_ViewController *weakSelf = self; 
    _observer = [[NSNotificationCenter defaultCenter] addObserverForName:backgroundColorIsGettingBoringNotification 
                    object:nil 
                    queue:[NSOperationQueue mainQueue] 
                   usingBlock:^(NSNotification *note){ 
                    [weakSelf observeHeyNotification:note]; 
                   }]; 
} 
-(void)viewDidUnload{ 
    [super viewDidUnload]; 
    [[NSNotificationCenter defaultCenter] removeObserver:_observer]; 
} 
-(void)dealloc{ 
    [[NSNotificationCenter defaultCenter] removeObserver:_observer]; 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{ 
    return (interfaceOrientation == UIInterfaceOrientationPortrait); 
} 
@end 

Il vantaggio principale di questa API sembra essere che il vostro blocco di osservazione sarà chiamata durante la chiamata postNotification.... Se è stato utilizzato l'API standard ed implementato observeHeyNotification: come la seguente non ci sarebbe alcuna garanzia per quanto tempo sarebbe passato prima che è stato eseguito il tuo blocco la spedizione:

-(void)observeHeyNotification:(NSNotification *)note{ 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     // Same stuff here... 
    }); 
} 

Naturalmente in questo esempio si potrebbe semplicemente non inviare la notifica su un thread in background, ma questo potrebbe tornare utile se si utilizza un framework che non fornisce garanzie su quale thread invierà le notifiche.

+0

Grazie, ottima spiegazione. Giusto per chiarire, 'addObserverForName' assicura che il blocco sia eseguito nello stesso thread a cui è legato l'osservatore (come nella stessa discussione hai chiamato' addObserverForName')? – Endophage

+0

@Endophage No. Il terzo parametro di 'addObserverForName: object: queue: usingBlock:' è un 'NSOperationQueue'. Il blocco viene eseguito sul thread/coda rappresentato da 'NSOperationQueue' passato. Nel codice di esempio della risposta ho usato il metodo di classe' mainQueue' per ottenere un riferimento alla coda principale/thread. – NJones

+2

Ah capito. Quindi in realtà una notifica può essere ricevuta su un thread diverso da quello su cui è stata generata passando l'appropriato 'NSNotificationQueue' quando si imposta l'osservatore. – Endophage

Problemi correlati