2013-08-15 5 views
3

Я пытаюсь понять концепцию RunLoops. Я прочитал руководство разработчика Apple по RunLoops и в некоторой степени понял концепцию RunLoops. Чтобы сделать мою концепцию более понятной, я написал очень простой код, в котором используется RunLoops. Код можно увидеть ниже.NSRunLoop- Требуется уточнение

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    thread = [[NSThread alloc] initWithTarget:self selector:@selector(testMethod) object:nil]; 
    [thread start]; 
} 

- (void)testMethod { 
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 

    NSLog(@"Thread Entered"); 

    NSMachPort* dummyPort = [[NSMachPort alloc] init]; 
    [[NSRunLoop currentRunLoop] addPort:dummyPort forMode:NSDefaultRunLoopMode]; 

    while(!exitThread) { 
     NSLog(@"Thread did some work"); 
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
    } 
    [[NSRunLoop currentRunLoop] 
    removePort:dummyPort 
    forMode:NSDefaultRunLoopMode]; 
    [dummyPort release]; 

    NSLog(@"Thread Exited"); 
    [pool drain]; 
} 

- (IBAction)doDomeWorkOnBackgroundThread:(id)sender { 
    [self performSelector:@selector(dummyMethod) onThread:thread withObject:nil waitUntilDone:NO]; 
} 

- (IBAction)exitThread:(id)sender { 
    [self performSelector:@selector(exitBackgroundThread) onThread:thread withObject:nil waitUntilDone:NO]; 
} 

- (void)exitBackgroundThread { 
    exitThread = YES; 
} 

- (void)dummyMethod { 
    //Empty 
} 

В коде выше я создаю фоновый поток и на этом фоне нить я звоню функцию testMethod. Внутри testmethod Я запускаю while, который проверяет переменную BOOL exitThread и запускает RunLoop фонового потока с использованием метода NSRunLoop - (BOOL)runMode: beforeDate:. Есть два IBActions, которые прикреплены к двум кнопкам. Поскольку имя IBActions предполагает, что один из них - exitThread, а другой - пробудить поток и выполнить инструкцию NSLog, записанную во время цикла while.

Приведенный выше код работает так, как я ожидал. Всякий раз, когда выполняется метод doDomeWorkOnBackgroundThread, поток просыпается из его runloop, выполняет следующую итерацию цикла while, проверяет переменную BOOL exitThread и находит ее значение как false, проходит внутри цикла while и выполняет инструкцию NSlog. Аналогично При использовании метода exitThread: переменная exitThread имеет значение true, из-за чего цикл while и поток завершаются.

Однако мне нужно несколько уточнений:

1) Если вместо того, чтобы использовать runMode: beforeDate: в цикле в то время как я использую run или runUntilDate: метод NSRunLoop, то поток никогда не выбрасываемые при exitThread: метод выполняется. Метод exitBackgroundThread вызывается в фоновом потоке, но цикл while никогда не выполняет его следующую итерацию (как при использовании runMode: beforeDate:), и поэтому поток никогда не выходит.

2) Я попытался изменить exitBackgroundThread метод

- (void)exitBackgroundThread { 
     exitThread = YES; 
     CFRunLoopStop(CFRunLoopGetCurrent()); 
    } 

Поскольку exitBackgroundThread выполняется на фоне резьбы CFRunLoopGetCurrent() должен дать RunLoop фонового потока. Поэтому это должно идеально остановить цикл запуска фонового потока независимо от того, какой метод NSRunLoop я использую для запуска RunLoop. Поэтому в любом случае поток должен выйти по вызову функции выше. Но этого просто не происходит.

Я знаю, что у меня что-то не хватает, и с моей стороны я делаю огромное количество googling, чтобы найти ответ на этот вопрос, но просто не могу найти правильный ответ.

** EDIT

Я нашел this вопрос, который очень похож на мой первый запрос. Это в значительной степени устраняет мои первые сомнения.

ответ

3
  1. Изменение вы видите, когда вы используете run или runUntilDate: вместо runMode:beforeDate: ожидается. Документация runMode:beforeDate: говорит, что это:

    возвращается после того, как первый источник входного сигнала обрабатывается или limitDate достигается.

    Существует источник входного сигнала, ответственный за обработку запросов performSelector:.... Поэтому, когда вы отправляете performSelector:..., цикл выполнения обрабатывает входной источник и затем возвращается.

    С другой стороны, документация run говорит, что это:

    он запускает приемник в NSDefaultRunLoopMode путем многократного вызова RunMode: beforeDate :. Другими словами, этот метод эффективно запускает бесконечный цикл, который обрабатывает данные из входных источников и таймеров цикла цикла.

    Итак, после того, как цикл запуска обработает источник входного сигнала для вашего запроса performSelector:..., он ждет, пока будет готов еще один источник входного сигнала. Он не возвращается. Так как он не возвращается, ваш цикл while никогда не получит возможность проверить exitThread.

  2. Попытка использовать CFRunLoopStop это хорошая идея, но, к сожалению, документация для run говорит, что это:

    Если вы хотите, чтобы цикл выполнения прекратить, вы не должны использовать этот метод. Вместо этого используйте один из других методов запуска, а также проверьте другие произвольные условия в цикле.

    Таким образом, вы не можете положиться на CFRunLoopStop, чтобы сделать run.

    Вместо этого, вы можете упасть до более низкого уровня и использовать CFRunLoopRun запустить цикл выполнения, так как CFRunLoopStop документирована, чтобы сделать эту функцию возврата:

    Эта функция силы rl остановить работу и возвращает управление функцию, которая вызвала CFRunLoopRun или CFRunLoopRunInMode для текущей активации цикла цикла.

    Так что попробуйте это запустить запустить цикл:

    while(!exitThread) { 
        NSLog(@"Thread did some work"); 
        CFRunLoopRun([NSRunLoop currentRunLoop].getCFRunLoop); 
    } 
    
+0

Привет, спасибо большое за такое подробное объяснение. Однако я мог найти CFRunLoopRun() только в документации. Но все-таки это сработало. – tek3

1

Документы runMode:beforeDate: говорят:

курсирует петлю один раз, блокирование ввода в заданном режиме до тех пор, данная дата.

Это означает, что процессы «@selector» источника входного сигнала только один раз, а затем возвращается, не так, как run будет продолжать обрабатывать следующий источник входного сигнала без возврата.

Однако runUntilDate: вернется после даты предельного если код как:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]]; 
Смежные вопросы