Запуск повторяющихся событий на Touch Down в iOS - PullRequest
2 голосов
/ 17 ноября 2011

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

В данный момент я запускаю операцию NSOperation для Touch Down, которая затем должна вызвать NSTimer для запуска другой операции NSO через 2 секунды.

Однако происходит только первая «операция запуска»; те из таймера не.

- (IBAction)buttonPressed:(id)sender
{
    [self doStuff];
}

- (void)runOperation {
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
                                                                            selector:@selector(doStuff)
                                                                          object:nil];

    [queue addOperation:operation];
    [operation release];
}

- (void)doStuff {
    /* stuff goes here */

    [self performSelectorOnMainThread:@selector(setTimer) withObject:nil waitUntilDone:YES];
}

- (void)setTimer
{
    timer = [[NSTimer timerWithTimeInterval:2.f target:self selector:@selector(runOperation) userInfo:nil repeats:NO] retain];
}

- (IBAction)finishTakingPictures:(id)sender {
    [timer invalidate];
    timer = nil;
}

Ответы [ 2 ]

2 голосов
/ 18 ноября 2011

XJones (безотносительно) прав насчет запланированного таймера и о нелепом количестве косвенных указаний. Но лично мне нравится NSTimer для этой модели взаимодействия с пользователем. Вот как я бы это реализовал.

_buttonTimer is an instance variable,
button is an IBOutlet to the button in question,
touchDown: is connected to the button's TouchDown event.

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

Затем добавьте эти методы в ваш подкласс UIViewController.

-(void)helloMe{
    if (self.button.state == UIControlStateNormal){ 
        [_buttonTimer invalidate];
        _buttonTimer = nil
    }
    else {
        NSLog(@"Hello me");
        // Do stuff here
    }
}

- (IBAction)touchDown:(id)sender {
    _buttonTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(helloMe) userInfo:nil repeats:YES];
    [_buttonTimer fire]; // If desired
}

Теперь запустите, вы увидите «Hello me» в консоли при нажатии кнопки и каждые две секунды, пока вы не отпустите кнопку.

1 голос
/ 17 ноября 2011

Чувак, надеюсь, это вам поможет, не знаю, почему я потратил столько времени на это ...:)

Если вы используете NSTimer:timerWithTimeInterval:..., вам нужно добавить таймер в цикл выполненияиспользуя NSRunLoop:addTimer:forMode.Вот почему ваш таймер не срабатывает.Если вы используете NSTimer:scheduledTimerWithTimeInerval:..., он будет добавлен к текущему циклу выполнения.

Несколько соображений по поводу вашей реализации.

  1. У вас много косвенных указаний.Вы можете установить его непосредственно в doStuff и избавиться от метода setTimer.

  2. Нет причин устанавливать таймер в главном потоке, вы можете установить его в любом потоке.

  3. Вам вообще не нужен таймер, я предложу альтернативную реализацию ниже.

АЛЬТЕРНАТИВНАЯ РЕАЛИЗАЦИЯ:

  1. Добавить свойство BOOL, например @property (nonatomic) BOOL isFinished;

  2. Когда пользователь нажимает кнопку, установите isFinished = NO; и начните свою первую операцию.

  3. Когда операция завершится, если isFinished == NO, начните другую операцию.Вы можете добавить задержку, используя performSelector:afterDelay: или dispatch_after()

  4. Когда пользователь перестает нажимать кнопку, установите isFinished = YES

Эта альтернативная реализация предполагает, что вы хотите начать следующую операцию после завершения первой.Если вы хотите, чтобы операция выполнялась после фиксированного интервала, независимо от того, обрабатывается ли уже какая-либо операция, измените свой таймер на повторение и, когда таймер сработает, проверьте isFinished == YES, чтобы сделать таймер недействительным.

...