2013-07-31 11 views
10

Jak czekać wewnątrz NSThread, aż pojawi się jakieś zdarzenie w systemie iOS?Jak czekać w NSThread, aż wydarzy się jakieś zdarzenie w systemie iOS?

np. Stworzyliśmy NSThread i uruchomiliśmy pętlę nitek. Wewnątrz pętli wątku istnieje warunek sprawdzenia, czy kolejka komunikatów zawiera jakieś komunikaty. Jeśli pojawi się komunikat, wywoła odpowiednią metodę, aby wykonać operację, inaczej powinien poczekać, aż kolejka komunikatów zapełni się nową wiadomością.

Czy istnieje jakieś API lub dostępne metody oczekiwania na wystąpienie zdarzenia?

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 (...) { 

    } 
} 

Każda pomoc powinna być doceniona.

Odpowiedz

13

Możesz użyć NSCondition. Załączam przykładowy kod "gotowy do testu" w 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

Dokładnie tego, czego szukałem. Świetny prosty, czysty przykład. –

+0

doskonały dobry przykład – ashokdy

2

Możesz użyć semafora. Zobacz przykład poniżej, logika jest po prostu prosta. Jestem moim przykładem, bloki są wykonywane w tle, a moja główna wątek czeka na sygnał wysyłania semafora. Główną różnicą jest w moim przypadku wątek oczekiwania jest głównym wątkiem, ale logika semaforów jest tutaj, myślę, że możesz łatwo dostosować to do swojej sprawy.

//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

Można użyć run loop sources. W istocie:

1) W dniu pracownika pomocniczego wątku utworzyć i zainstalować run źródło pętli, i przekazać go w jakiś sposób, wraz z wątku roboczego odniesienia pętli run, do innego zarządzającego wątku będzie wysyłanie wiadomości do tego:

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 

Tutaj są niestandardowe procedury wymienione powyżej - jesteś odpowiedzialny, aby zapewnić im:

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) W wątku roboczego, zaczynają zwykle pętlę biegać, coś podobnego do tego:

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

3) Teraz na zarządzaniu wątek można sygnału (wysłać wiadomość) do uprzednio otrzymanej źródła pętli uruchomić w razie potrzeby (i obudzić pętlę przebiegu tych nici w przypadku, gdy jest w stanie uśpienia):

CFRunLoopSourceSignal(runLoopSource); 
    CFRunLoopWakeUp(workerThreadRunLoop); 

Więcej szczegółów znajduje się w Apple's guide.

Powiązane problemy