Как ждать в NSThread, пока в iOS не произойдет какое-то событие?
Как ждать внутри NSThread, пока в iOS не произойдет какое-то событие?
Например, мы создали 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 ответа
Вы можете использовать NSCondition. Я прилагаю пример кода "готов для теста" в 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];
}
Вы можете использовать источники цикла выполнения. По сути:
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.
Вы можете использовать семафор. Смотрите пример ниже, логика довольно проста. В моем примере блоки выполняются в фоновом режиме, и мой основной поток ожидает продолжения сигнала диспетчеризации семафора. Основное отличие состоит в том, что в моем случае ожидание потока является основным потоком, но логика семафора здесь, я думаю, вы можете легко адаптировать это к своему случаю.
//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]];
}