Лучший способ заставить NSRunLoop ожидать флага, который будет установлен?

Вызов read() читает весь файл и оставляет курсор чтения в конце файла (ничего больше не читать). Если вы хотите прочитать определенное количество строк за раз, вы можете использовать readline(), readlines() или перебирать строки с помощью for line in handle:.

Чтобы ответить на ваш вопрос напрямую, был прочитан, с read() вы можете использовать seek(0), чтобы вернуть курсор чтения к началу файла (docs здесь ). Если вы знаете, что файл не будет слишком большим, вы также можете сохранить вывод read() в переменной, используя его в выражениях поиска.

Ps. Не забудьте закрыть файл после его завершения;)

39
задан Ned Batchelder 9 November 2008 в 21:51
поделиться

6 ответов

Runloops может быть чем-то вроде волшебного поля, где материал просто происходит.

В основном Вы говорите, что runloop для движения обрабатывают некоторые события и затем возвращаются. ИЛИ возвратитесь, если это не обрабатывает событий, прежде чем тайм-аут будет поражен.

С 0,1 вторыми тайм-аутами, Вы - htting тайм-аут, как правило. Огни runloop, не обрабатывает событий и возвратов в 0.1 из вторых. Иногда это будет получать шанс обработать событие.

С Вашим distantFuture тайм-аутом, runloop будет ожидать навсегда, пока это не обработает событие. Таким образом, когда это возвращается к Вам, это только что обработало событие некоторого вида.

А короткое значение тайм-аута использует значительно больше ЦП, чем бесконечный тайм-аут, но существуют серьезные основания для использования короткого тайм-аута, например, если Вы хотите завершить процесс/поток, runloop работает в. Вы, вероятно, захотите, чтобы runloop заметил, что флаг изменился и что это должно прыгнуть с парашютом как можно скорее.

Вы могли бы хотеть играть вокруг с runloop наблюдателями, таким образом, Вы видите точно, что делает runloop.

См. этот документ Apple для получения дополнительной информации.

36
ответ дан Christian Di Lorenzo 12 November 2019 в 13:24
поделиться

Хорошо, я объяснил Вас проблема, вот возможное решение:

@implementation MyWindowController

volatile BOOL pageStillLoading;

- (void) runInBackground:(id)arg
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // Simmulate web page loading
    sleep(5);

    // This will not wake up the runloop on main thread!
    pageStillLoading = NO;

    // Wake up the main thread from the runloop
    [self performSelectorOnMainThread:@selector(wakeUpMainThreadRunloop:) withObject:nil waitUntilDone:NO];

    [pool release];
}


- (void) wakeUpMainThreadRunloop:(id)arg
{
    // This method is executed on main thread!
    // It doesn't need to do anything actually, just having it run will
    // make sure the main thread stops running the runloop
}


- (IBAction)start:(id)sender
{
    pageStillLoading = YES;
    [NSThread detachNewThreadSelector:@selector(runInBackground:) toTarget:self withObject:nil];
    [progress setHidden:NO];
    while (pageStillLoading) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
    [progress setHidden:YES];
}

@end

запускаются дисплеи индикатор хода выполнения, и получает основной поток во внутреннем runloop. Это останется там, пока другой поток не объявляет, что это сделано. Для пробуждения основного потока это заставит его обработать функцию без цели кроме пробуждения основного потока.

Это - всего один путь, как можно сделать это. Уведомление, отправляемое и обработанное на основном потоке, могло бы быть предпочтительным (также другие потоки могли зарегистрироваться для него), но решение выше является самым простым, я могу думать. BTW это не действительно ориентировано на многопотоковое исполнение. Чтобы действительно быть ориентированным на многопотоковое исполнение, каждый доступ к булевской переменной должен быть заблокирован объектом NSLock от любого потока (использующий такую блокировку, также делает "энергозависимым" устаревший, поскольку переменные, защищенные блокировкой, неявны энергозависимый согласно стандарту POSIX; стандарт C однако не знает о блокировках, таким образом, здесь только энергозависимый может гарантировать этот код для работы; GCC не нужно энергозависимый, чтобы быть установленным для переменной, защищенной блокировками).

15
ответ дан Mecki 12 November 2019 в 13:24
поделиться

Если Вы хотите быть в состоянии установить свою переменную флага и иметь цикл выполнения, сразу замечают, просто используют -[NSRunLoop performSelector:target:argument:order:modes: , чтобы попросить, чтобы цикл выполнения вызвал метод, который устанавливает флаг на ложь. Это заставит Ваш цикл выполнения сразу вращаться, метод, который будет вызван, и затем флаг будет проверен.

10
ответ дан Chris Hanson 12 November 2019 в 13:24
поделиться

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

, Если Вы хотите работать модально - например, показывая панель прогресса - выполненный модально! Разрешение и использование, методы NSApplication, выполненные модально для листа прогресса, затем останавливают модальное, когда загрузка сделана. См. документацию Apple, например http://developer.apple.com/documentation/Cocoa/Conceptual/WinPanel/Concepts/UsingModalWindows.html .

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

- (IBAction)start:(id)sender
{
    pageStillLoading = YES;
    [NSThread detachNewThreadSelector:@selector(runInBackground:) toTarget:self withObject:nil];
    [progress setHidden:NO];
}

- (void)wakeUpMainThreadRunloop:(id)arg
{
    [progress setHidden:YES];
}

И Вы сделаны. Никакая потребность удержать контроль над циклом выполнения!

-Wil

11
ответ дан Wil Shipley 12 November 2019 в 13:24
поделиться

I’ve имел подобные проблемы при попытке справиться NSRunLoops. обсуждение для runMode:beforeDate: на странице ссылок класса говорит:

, Если никакие входные источники или таймеры не присоединены к циклу выполнения, этот метод сразу выходит; иначе это возвращается, или после первый входной источник обрабатывается или после limitDate, достигнут. Вручную удаление всех известных входных источников и таймеров от цикла выполнения не является гарантией, что цикл выполнения выйдет. Mac OS X может установить и удалить дополнительные входные источники по мере необходимости для обработки запросов, предназначенных для потока receiver’s. Те источники могли поэтому препятствовать тому, чтобы цикл выполнения вышел.

Мое лучшее предположение - то, что входной источник присоединен к Вашему NSRunLoop, возможно, самим OS X, и что runMode:beforeDate: блокируется до того входного источника или имеет некоторый вход, обработанный, или удален. В Вашем случае это брало" несколько секунд и до 10 секунд " для этого для случая, в котором точка runMode:beforeDate: возвратится с булевской переменной, эти while() работал бы снова, это обнаружит, что shouldKeepRunning был установлен на NO, и цикл завершится.

С Вашим улучшением эти runMode:beforeDate: возвратится в течение 0,1 секунд, независимо от того, присоединило ли оно входные источники или обработало какой-либо вход. Это - образованное предположение (я не эксперт по внутренностям цикла выполнения), но думайте, что Ваше улучшение является правильным способом обработать ситуацию.

2
ответ дан 2 revs, 2 users 86% 12 November 2019 в 13:24
поделиться

В Вашем коде текущий поток проверит на переменную для изменения каждую 0.1 секунды. В примере кода Apple, заменяя не будет иметь никакого эффекта. runloop будет работать, пока он не обработает некоторое событие. Если значение webViewIsLoading изменилось, никакое событие не сгенерировано автоматически, таким образом это останется в цикле, почему это убежало бы из него? Это останется там, пока это не заставит некоторое другое событие обрабатывать, затем это убежит из него. Это может произойти в 1, 3, 5, 10 или даже 20 секунд. И пока этого не происходит, это не убежит из runloop, и таким образом это не заметит, что эта переменная изменилась. IOW код Apple, который Вы заключили в кавычки, является indeterministic. Этот пример будет только работать, если изменение значения webViewIsLoading также создаст событие, которое заставляет runloop просыпаться, и это, кажется, не имеет место (или по крайней мере не всегда).

Я думаю, что необходимо заново продумать проблему. Так как Вашу переменную называют webViewIsLoading, Вы ожидаете веб-страницы, которая будет загружена? Вы используете WebKit для этого? Я сомневаюсь, что Вам нужны такая переменная вообще, ни любой код, который Вы отправили. Вместо этого необходимо кодировать приложение асинхронно. Необходимо запустить "процесс загрузки веб-страницы" и затем вернуться к основному циклу и как только страница закончила загружаться, необходимо асинхронно отправить уведомление, которое обрабатывается в основном потоке и выполняет код, который должен работать, как только загрузка закончилась.

5
ответ дан Mecki 27 November 2019 в 02:29
поделиться