如何将选择器或块发送到NSRunLoop来执行?

如何将选择器或块发送到NSRunLoop来执行?

问题描述:

我需要保证相同的线程在任意时间执行各种操作。首先线程需要初始化一个库,然后我希望线程休眠直到工作需要完成,并且在用户输入时,我需要能够传递选择器或块来执行。如何将选择器或块发送到NSRunLoop来执行?

如何在初始化后设置NSRunLoop进入睡眠状态?在此之后,我如何指示运行循环唤醒并执行某些操作?

我试过读的是iOS线程编程指南,但我希望避免设立类作为自定义输入类,并使用一些更轻巧喜欢performSelector:onThread:

我可以设置一个计时器永远火从现在开始,运行循环不会结束?

这里的基本上是我想要的伪代码:

// Initialization Code... 

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

在哪里我送的工作做一个performSelector:onThread:消息。如果我可以发送运行循环一个块,它会更好:^{[someObj message]; [otherObj otherMsg];},但我很乐意与performSelector,因为我非常肯定这可能没有多少额外的编码。

谢谢!

你在你的问题中有所有必要的作品。你开始你的线程并让它运行它的runloop。如果你需要线程来做一些事情,你可以在主线程上使用performSelector:onThread:来做到这一点。

runloop有一点你必须知道,但它不会运行,除非它有一个输入源或附加的定时器。只需将计时器附加到在遥远的将来发生一段时间的运行循环中,并且您已全部设置好。

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

使用performSelector:onThread:withObject:您还可以将块传递给后台线程。所有你需要做的是写一个方法的地方,需要一个块作为一个参数并运行它:

@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 

但是,也许你应该使用调度队列,而不是这一切。这需要更少的代码,并可能有更少的开销也:

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]; 
}); 

使用dispatch_queue_create创建的调度队列是一个串行队列 - 发送给它的所有块将在他们到达了,一个又一个相同的顺序进行。

+0

感谢您的代码示例!我最初使用的是分派队列,但如果分派之间的时间太长,它不会重用相同的线程。 – 2010-10-15 15:16:20

+0

是的,这是真的。但它并不重要,除非你的库代码依赖于它运行的是哪个线程。通常情况并非如此。即使你的图书馆说它不是线程安全的,只要它不是同时调用多个线程*就没关系了。串行队列永远不会发生这种情况。 – Sven 2010-10-15 15:26:13

+1

我正在使用的库是PJSUA,当它检测到调用线程与初始化线程不同时,断言失败时:( – 2010-10-15 17:46:27

我想你可以使用NSInvocationOperation与NSOperationQueue。

+1

如果调用之间的时间太长,操作队列不会重用相同的线程。 (还是)感谢你的建议。 – 2010-10-15 15:15:41

考虑使用NSConditionLock。它被设计用于这样的任务。想象一下,你有一个数据队列。第一个线程将数据添加到队列中,第二个线程等待数据并对其进行处理。

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. 
}