2010-10-15 12 views
13

Ich muss garantieren, dass der gleiche Thread verschiedene Aktionen zu beliebigen Zeiten ausführt. Zuerst muss der Thread eine Bibliothek initialisieren, dann möchte ich den Thread in den Ruhezustand versetzen, bis die Arbeit erledigt ist, und nach der Benutzereingabe muss ich in der Lage sein, Selektoren oder Blöcke zur Ausführung zu übergeben.Wie können Selektoren oder Blöcke an einen NSRunLoop gesendet werden?

Wie kann ich einen NSRunLoop einrichten, um nach der Initialisierung zu schlafen? Wie kann ich der Run-Schleife signalisieren, dass sie aufwacht und etwas unternimmt?

Ich habe versucht, das Threading-Programmierhandbuch für iOS zu lesen, aber ich mag Klassen Eingangsklassen als individueller Einrichtung vermeiden und etwas leichter verwenden wie performSelector:onThread:

Kann ich einen Timer einstellen, für immer Feuer ab jetzt läuft die Laufschleife nicht?

Hier ist im Wesentlichen, was ich in Pseudo-Code will:

// Initialization Code... 

do { 
    sleepUntilSignaled(); 
    doWorkSentToThisThread(); 
while (!done); 

Wo ich die Arbeit schicken als performSelector:onThread: Nachricht zu tun. Es wäre noch besser, wenn ich der Laufschleife einen Block wie: ^{[someObj message]; [otherObj otherMsg];} senden könnte, aber ich wäre glücklich mit performSelector, da ich mir ziemlich sicher bin, dass das ohne viel extra Codierung möglich ist.

Danke!

Antwort

8

Sie haben alle notwendigen Teile zusammen in Ihrer Frage. Du startest deinen Thread und lässt ihn laufen. Wenn Sie den Thread benötigen, um etwas zu tun, können Sie performSelector:onThread: auf dem Hauptthread dazu verwenden.

Es gibt eine Sache mit der Runloop müssen Sie jedoch beachten: Es wird nicht ausgeführt, es sei denn, es hat eine Eingabequelle oder einen Timer an es angeschlossen. Schließen Sie einfach einen Timer an die Laufschleife an, die in der fernen Zukunft Zeit verströmt und Sie sind bereit.

// Initialization code here 

[NSTimer scheduledTimerWithTimeInterval: FLT_MAX 
           target: self selector: @selector(doNothing:) 
           userInfo: nil repeats:YES]; 

NSRunLoop *rl = [NSRunLoop currentRunLoop]; 
do { 
    [rl runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
} while (!done); 

Mit performSelector:onThread:withObject: können Sie auch Ihren Block an den Hintergrund Thread übergeben. Alles was Sie tun müssen, ist eine Methode irgendwo zu schreiben, die einen Block als Parameter übernimmt und es läuft:

@interface NSThread (sendBlockToBackground) 
- (void) performBlock: (void (^)())block; 
@end 

@implementation NSThread (sendBlockToBackground) 
- (void) performBlock: (void (^)())block; 
{ 
    [self performSelector: @selector(runBlock:) 
       onThread: self withObject: block waitUntilDone: NO]; 
} 

- (void) runBlock: (void (^)())block; 
{ 
    block(); 
} 
@end 

Aber vielleicht sollten Sie eine Absende-Warteschlange statt all diese verwenden. Dies erfordert weniger Code und hat wahrscheinlich weniger Aufwand auch:

dispatch_queue_t myQueue = dispatch_queue_create("net.example.product.queue", NULL); 
dispatch_async(myQueue, ^{ 
    // Initialization code here 
}); 

// Submit block: 
dispatch_async(myQueue, ^{ 
    [someObject someMethod: someParameter]; 
}); 

A mit dispatch_queue_create erstellt Absende-Warteschlange eine serielle Warteschlange ist - alle Blöcke an ihn gesendet werden in der gleichen Reihenfolge durchgeführt werden, sie kamen, einer nach dem anderen.

+0

Danke für die Codebeispiele! Ich habe ursprünglich eine Dispatch-Warteschlange verwendet, aber es wird nicht den gleichen Thread wiederverwendet, wenn zwischen den Versendungen zu viel Zeit ist. –

+0

Ja, das stimmt. Aber es ist nicht wirklich wichtig, es sei denn, Ihr Bibliothekscode hängt davon ab, in welchem ​​Thread er ausgeführt wird.Dies ist normalerweise nicht der Fall. Auch wenn Ihre Bibliothek sagt, dass es nicht threadsicher ist, spielt dies keine Rolle, solange es nicht von mehr als einem Thread * gleichzeitig aufgerufen wird *. Und das wird nie mit einer seriellen Warteschlange passieren. – Sven

+1

Die Bibliothek, die ich benutze, ist PJSUA und wenn es Assertions fehlschlägt, wenn es feststellt, dass ein aufrufender Thread anders ist als der initialisierende Thread :( –

0

Ich denke, Sie können NSInvocationOperation mit NSOperationQueue verwenden.

+1

Operationswarteschlangen verwenden den gleichen Thread nicht erneut, wenn die Zeit zwischen den Aufrufen zu lang ist. Danke für den Vorschlag. –

2

Verwenden Sie NSConditionLock. Es ist für solche Aufgaben konzipiert. Stellen Sie sich vor, Sie haben eine Warteschlange mit Daten. Der erste Thread fügt Daten zur Warteschlange hinzu, der zweite Thread wartet auf Daten und verarbeitet sie.

id condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA]; 

//First thread 
while(true) 
{ 
    [condLock lock]; 
    /* Add data to the queue. */ 
    [condLock unlockWithCondition:HAS_DATA]; 
} 

//Second thread 
while (true) 
{ 
    [condLock lockWhenCondition:HAS_DATA]; 
    /* Remove data from the queue. */ 
    [condLock unlockWithCondition:(isEmpty ? NO_DATA : HAS_DATA)]; 

    // Process the data locally. 
} 
Verwandte Themen