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

时间:2013-07-31 13:26:25

标签: iphone ios objective-c nsthread nsrunloop

如果在iOS中发生某些事件之前如何在NSThread内等待?

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

是否有任何API或方法可以等到某个事件发生?

For Example 

NSThread *thread = [NSThread alloc]....@selector(threadLoop)

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

   }
}

任何帮助都应该受到赞赏。

3 个答案:

答案 0 :(得分:14)

您可以使用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];
}

答案 1 :(得分: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

答案 2 :(得分: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]];
}