2011-09-22 5 views
13

UIView ha un metodo setNeedsDisplay che è possibile chiamare più volte all'interno dello stesso ciclo di eventi, con la certezza che il lavoro di ridisegno avverrà presto e solo una volta.C'è un modo semplice (in Cocoa/iOS) per mettere in coda una chiamata al metodo da eseguire una volta nel ciclo di esecuzione successivo?

Esiste un meccanismo generico per questo tipo di comportamento Cocoa? Un modo per dire: "Metti in coda un selettore tutte le volte che vuoi, quando è il momento, il selettore verrà eseguito una volta che & cancella la coda."

So che potrei farlo con una sorta di tracciamento di stato nel mio obiettivo, o con un NSOperationQueue. Mi stavo chiedendo se c'è un approccio leggero che mi è mancato.

(Naturalmente, la risposta potrebbe essere: "No".)

+0

@Bavarious Ho usato UIKit come esempio, ma penso che la domanda si applichi in generale a Cocoa, vero? –

+0

Probabilmente. Se sei sicuro che ogni approccio su Mac OS X si applica alla tua domanda, sentiti libero di aggiungere il tag cacao. –

risposta

12

setNeedsDisplay non è un buon esempio di quello che stai descrivendo, dal momento che in realtà viene eseguito ogni volta che si chiama. Imposta solo una bandiera. Ma la domanda è buona.

Una soluzione è utilizzare NSNotificationQueue con NSNotificationCoalescingOnName.

Un'altra soluzione è quella di costruire un trampolino per fare da solo la coalescenza. Non ho un buon blog di riferimento per trampolini, ma ecco un esempio di uno (LSTrampoline). Non è così difficile costruirlo se vuoi unire i messaggi per un periodo di tempo. Una volta ho costruito un trampolino con un forwardInvocation: simile a questo:

- (void)forwardInvocation:(NSInvocation *)invocation { 
    [invocation setTarget:self.target]; 
    [invocation retainArguments]; 
    [self.timer invalidate]; 
    self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeout invocation:invocation repeats:NO]; 
} 

fonde Questo in realtà tutti i messaggi per l'oggetto nel periodo di tempo (non solo messaggi corrispondenti). Questo è tutto ciò di cui avevo bisogno per il particolare problema. Ma potresti ampliarlo per tenere traccia di quali selettori vengono coalizzati e controllare le tue invocazioni per vedere se corrispondono "sufficientemente".

Per ottenere questo per eseguire sul prossimo ciclo di eventi, è sufficiente impostare il timeout a 0.

Continuo senso di blog su trampolini. Shilling richiesto: Il mio upcoming book copre trampolini nel Capitolo 4 e il Capitolo 20.

+2

Risposta fantastica, e penso che NSNotificationCoalescingOnName sia esattamente quello che stavo cercando. :-) –

6
[NSObject cancelPreviousPerformRequestsWithTarget:self 
             selector:@selector(doTheThing:) 
              object:someObject]; 
[self performSelector:@selector(doTheThing:) 
      withObject:someObject 
      afterDelay:0]; 

questo non è esattamente come UIView sta facendo perché setNeedsDisplay definisce semplicemente una bandiera e l'UIView meccanismo interno fa in modo di chiamare drawRect: dopo aver configurato la ambiente di disegno, ma questo è un modo generico e non richiede alcun monitoraggio di stato speciale nella tua classe.

+1

Tieni presente che la chiamata a "cancelPreviousPerformRequest ..." può essere estremamente lenta. In molti casi va bene, ma se chiamato molto spesso può essere un problema. –

Problemi correlati