2013-07-31 8 views
10

Wie in der NSThread warten, bis ein Ereignis in iOS auftreten?Wie in NSThread warten, bis ein Ereignis in iOS auftreten?

zB Wir haben einen NSThread erstellt und eine Thread-Schleife gestartet. Innerhalb der Thread-Schleife gibt es eine Bedingung, um zu überprüfen, ob die Nachrichtenwarteschlange Nachrichten enthält. Wenn eine Nachricht vorhanden ist, ruft sie die entsprechende Methode auf, um eine Operation auszuführen, andernfalls sollte sie warten, bis die Nachrichtenwarteschlange mit einer neuen Nachricht gefüllt wird.

Gibt es eine API oder Methoden, die warten können, bis ein Ereignis eintritt?

For Example 

NSThread *thread = [NSThread alloc][email protected](threadLoop) 

- (void)threadLoop 
{ 
    // Expecting some API or method that wait until some messages pushed into the message queue 
    if (...) { 

    } 
} 

Jede Hilfe sollte geschätzt werden.

Antwort

13

Sie können NSCondition verwenden. Ich lege Beispielcode "ready-for-Test" in einem Viewcontroller

@interface ViewController() 

@property (strong, nonatomic) NSCondition *condition; 
@property (strong, nonatomic) NSThread *aThread; 

// use this property to indicate that you want to lock _aThread 
@property (nonatomic) BOOL lock; 

@end 

@implementation ViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    // start with the thread locked, update the boolean var 
    self.lock = YES; 

    // create the NSCondition instance 
    self.condition = [[NSCondition alloc]init]; 

    // create the thread and start 
    self.aThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadLoop) object:nil]; 
    [self.aThread start]; 

} 

-(void)threadLoop 
{ 
    while([[NSThread currentThread] isCancelled] == NO) 
    { 
     [self.condition lock]; 
     while(self.lock) 
     { 
      NSLog(@"Will Wait"); 
      [self.condition wait]; 

      // the "did wait" will be printed only when you have signaled the condition change in the sendNewEvent method 
      NSLog(@"Did Wait"); 
     } 

     // read your event from your event queue 
     ... 


     // lock the condition again 
     self.lock = YES; 
     [self.condition unlock]; 
    } 

} 

- (IBAction)sendNewEvent:(id)sender { 
    [self.condition lock]; 
    // put the event in the queue 
    ... 


    self.lock = NO; 
    [self.condition signal]; 
    [self.condition unlock]; 
} 
+0

Genau das, was ich suchte. Tolles einfaches, sauberes Beispiel. –

+0

ausgezeichnet gutes Beispiel – ashokdy

2

Sie können ein Semaphor verwenden. Siehe das folgende Beispiel, die Logik ist ziemlich einfach. In meinem Beispiel werden die Blöcke im Hintergrund ausgeführt, und mein Hauptthread wartet auf das Abfertigungssignal des Semaphors, um weiterzugehen. Der Hauptunterschied ist in meinem Fall, dass der Threadwarteprozess der Hauptthread ist, aber die Semaphorlogik ist hier, ich denke, Sie können dies leicht an Ihren Fall anpassen.

//create the semaphore 
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 

[objectManager.HTTPClient deletePath:[address addressURL] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { 

     //some code here 

     dispatch_semaphore_signal(semaphore); 

    }failure:^(AFHTTPRequestOperation *operation, NSError *error) { 

     //some other code here 

     dispatch_semaphore_signal(semaphore); 
    }]; 

//holds the thread until the dispatch_semaphore_signal(semaphore); is send 
while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) 
{ 
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; 
} 
3

Sie könnten run loop sources verwenden. Im wesentlichen:

1) Auf Sekundär Arbeiter-Thread erzeugen und Laufschleifenquelle installieren, und übergibt es irgendwie, zusammen mit Arbeiter-Thread Laufschleife Referenz, auf anderen Verwaltung Threads, Nachrichten an diesen zu senden wird:

CFRunLoopSourceContext context = {0, self, NULL, NULL, NULL, NULL, NULL, 
            &RunLoopSourceScheduleRoutine, 
            RunLoopSourceCancelRoutine, 
            RunLoopSourcePerformRoutine}; 
    CFRunLoopSourceRef runLoopSource = CFRunLoopSourceCreate(NULL, 0, &context); 
    CFRunLoopRef runLoop = CFRunLoopGetCurrent(); 
    CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode); 
    // Pass runLoopSource and runLoop to managing thread 

Hier gibt es benutzerdefinierte Routinen oben erwähnt - Sie sind dafür verantwortlich, sie zu bieten:

RunLoopSourceScheduleRoutine - called when you install run loop source (more precisely, when you call CFRunLoopAddSource) 

    RunLoopSourceCancelRoutine - called when you remove run loop source (more precisely, when you call CFRunLoopSourceInvalidate) 

    RunLoopSourcePerformRoutine - called when run loop source was signaled (received a message from manager thread) and this is a place where you should perform a job 

2) auf worker-Thread starten üblichen Laufschleife, etwas ähnliches wie folgt aus:

BOOL done = NO; 
    do { 
     int result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, YES); 
     done = (result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished); 
    } while (!done); 

3) nun auf Thread verwalten Sie signalisieren könnte (senden Nachricht) an zuvor empfangene Quelllaufschleife bei Bedarf (und wecken die Laufschleife jener Faden bei bis es schläft):

CFRunLoopSourceSignal(runLoopSource); 
    CFRunLoopWakeUp(workerThreadRunLoop); 

Weitere Details sind in Apples guide.

Verwandte Themen