Как подождать в 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 (...) {
}
}
Любая помощь должна быть оценена.
Ответы
Ответ 1
Вы можете использовать NSCondition.
Я прикрепляю примерный код "ready-for-test" в 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];
}
Ответ 2
Вы можете использовать запустить источники цикла. По существу:
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.
Ответ 3
Вы можете использовать семафор. См. Пример ниже, логика довольно проста. В моем примере блоки выполняются в фоновом режиме, и мой основной поток ожидает, чтобы сигнал отправки семафора продолжался. Главное отличие в моем случае - ожидание потока - это основной поток, но логика семафора здесь, я думаю, вы можете легко адаптировать это к вашему делу.
//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]];
}