Как заставить NSTimer зацикливаться

#objective-c #macos #nstimer #foundation

#objective-c #macos #nstimer #основа

Вопрос:

Я пытаюсь узнать о NSTimer , использовании Foundation и печати на консоли. Кто-нибудь может сказать мне, что мне нужно сделать, чтобы заставить следующее работать? Он компилируется без ошибок, но не активирует мой startTimer метод — ничего не печатается.

Моя цель — заставить один метод вызывать другой метод для выполнения некоторых инструкций, а затем останавливаться через установленное время.

 #import <Foundation/Foundation.h>

@interface MyTime : NSObject {
    NSTimer *timer;
}
- (void)startTimer;
@end

@implementation MyTime

- (void)dealloc {
    [timer invalidate];
    [super dealloc];
}

- (void)startTimer {
     timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(runTimer:) userInfo:nil repeats:YES];
}

- (void)runTimer:(NSTimer *)aTimer {
    NSLog(@"timer fired");
}
@end


int main(int argc, char *argv[]) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];


    MyTime *timerTest = [[MyTime alloc] init];
    [timerTest startTimer];

    [timerTest release];

    [pool release];
    return 0;
}
  

Комментарии:

1. Пожалуйста, вознаградите людей, которые помогали вам в прошлом, и примите ответы на ваш старый вопрос.

Ответ №1:

Таймер никогда не получает возможности сработать в вашей программе, потому что программа завершается почти сразу после создания таймера.

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

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

 [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];
  

между отправкой startTimer и release в timerTest . Если вы хотите, чтобы таймер повторился, вам нужно продолжать поддерживать цикл выполнения активным.

Обратите внимание, что вам нужно сделать это только в такой простой программе, как эта; когда вы создаете приложение с графическим интерфейсом, цикл выполнения будет запущен через процесс настройки приложения Cocoa и будет оставаться активным до завершения работы приложения.

Комментарии:

1. Я не думаю, что будет достаточно точно сказать «когда завершается основная функция, завершается и цикл выполнения». Я имею в виду, это правда, что выход программы завершит цикл выполнения, но проблема здесь не в этом. В этом конкретном примере цикл выполнения даже не запускается.

2. @Chuck: На самом деле я только что пытался разобраться с этим вопросом. У меня создалось впечатление, что цикл был запущен автоматически потоком [NS?], но я предполагаю, что на самом деле это сделано AppKit?

3. У каждого NSThread есть цикл выполнения, но он не запускается, пока ему не будет указано. В обычном приложении Cocoa основной цикл выполняется NSApplicationMain() . Я думаю, что это то, на что он ссылается в документах, когда говорится, что функция «запускает приложение».

4. @pete: Рад, что это помогло. Пожалуйста, не забудьте поставить галочку напротив этого и ответов на другие ваши вопросы, когда они решат вашу проблему. Это позволяет другим узнать, что вопрос решен, и вознаграждает ответившего. Смотрите meta.stackexchange.com/q/5234 для получения подробной информации, как я ссылался выше.

Ответ №2:

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

 [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
  

Поместите это в -(void)startTimer.

Комментарии:

1. Я только что скопировал и вставил это в -(void)startTimer startTimer, но он все еще не работает. Если поместить выше инструкции timer, она ничего не делает, как раньше. Если поместить его ниже, я получу поток! серьезная ошибка. Что предложить, выглядит хорошо — не могли бы вы попробовать еще раз? спасибо Тиму.

2. Поместить его ниже — правильное место для его размещения. Проблема в том, что в вашей программе вы запускаете таймер, а затем немедленно освобождаете содержащий его объект, и он все еще находится в цикле выполнения, поэтому при его вызове объект, с которым он работает (в данном случае testTimer ), уже исчез, и именно поэтому вы получаете сообщение об ошибке.

3. Это правильно, только если вы не используете семейство классов scheduledTimer, которое использует он.

4. Я переместил его ниже, как было предложено, и удалил [timerTest release]; но он все еще не работает —

5. итак, есть идеи о том, как я могу достичь своей первоначальной цели, как указано выше?