2013-07-31 48 views
10

如何在NSThread内部等待,直到iOS中发生某些事件?如何等待NSThread,直到iOS中发生某些事件?

例如,我们创建了一个NSThread,并开始一个线程循环。在线程循环中,有条件检查消息队列是否有任何消息。如果有消息,那么它会调用相应的方法来执行一些操作,否则它应该等到消息队列填充新消息。

是否有任何可用的API或方法来等待某些事件发生?

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

    } 
} 

任何帮助,应该理解。

回答

13

您可以使用NSCondition。 我在ViewController中附加示例代码“ready-for-test”

@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

正是我在找的东西。非常简单,干净的例子。 –

+0

非常好的例子 – ashokdy

2

您可以使用信号量。看下面的例子,逻辑非常简单。我的例子,块在后台执行,我的主线程等待信号量的调度信号继续。主要区别在于我的情况线程等待是主线程,但信号逻辑在这里,我认为你可以很容易地适应你的情况。

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

您可以使用run loop sources。从本质上说:

1)在次级工作线程创建和安装运行循环源,并以某种方式通过它,与工作线程运行的循环引用一起,对其他管理线程将要发送消息给这一个:

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 

这里有上面提到的自定义程序 - 你有责任为他们提供:

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)在工作线程,开始通常的运行循环,类似这样:

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

3)现在,在管理线程你能信号(在需要时发送消息)之前接收到的运行循环源(和唤醒这些线程的运行循环的情况下,它是睡着了):

CFRunLoopSourceSignal(runLoopSource); 
    CFRunLoopWakeUp(workerThreadRunLoop); 

更多细节请参阅Apple的guide