[iOS/OSX] Timer 사용하기

특정한 시간 이후에 작업을 시행하는 타이머를 사용하는 방법에는 몇 가지 방법이 있을 수 있는데, 코코아에서 타이머는 NSTimer 객체를 통해 구현된다.

타이머와 런루프

타이머는 런루프(Run Loop)와 밀접한 관련을 맺고 있다. 타이머는 스스로 동작기한을 가지고 있고, 그 상태로 런루프에 등록된다. 런루프는 그 기한이 지나는 시점에 타이머를 지켜보고 있다가, 타이머가 실행하기로 한 액션을 지정된 객체로 보내게 된다.

런루프는 (역시나 런루프와 스레드를 혼동하는 불편한 진실 때문에 이에 대한 별도의 포스팅도 필요할 듯) 사용자의 입력 등에 적절히 반응하기 위해서 계속해서 “기다리는” 일종의 루프이다. 예를 들면 키보드는 풀링이라는 방식으로 일종의 런루프를 가지고 있다. 즉 사용자가 키보드를 누르지 않는 상황에서 키보드는 ‘최선을, 총력을 다해서’ 사용자 입력을 반복해서 기다린다. 런루프는 이와 유사하게 스레드 내에서 사용자의 UI 입력을 최선을 다해 기다린다.

타이머가 지정한 액션은 런루프에 의해서 확인된다. 타이머를 사용할 때 가장 유의해야 하는 점은 NSTimer는 실시간 타이머가 아니라는 점이다. 만약 반복되는 주기를 가진 타이머의 특정 작업이 있다고 할 때, 런루프는 단지 그 타이머만을 감시하는 것이 아니라 아주 많은 종류의 입력을 처리해야 하기 때문에 이를 놓치는 경우가 있을 수 있다. 따라서 NSTimer를 통해 이뤄지는 지연된 작업이나, 반복작업은 실제 시간과 다소 차이가 있을 수 있으며, 경우에 따라서는 “상당히 큰” 차이가 발생할 수 있다.

타이머 사용하기

스케줄된 타이머 사용하기

타이머를 사용하는 가장 일반적인 방법은 NSTImer의 scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: 를 사용하는 방법이다. 이는 현재 메인 런루프에 타이머를 추가한다.

-(void)startOneOffTimer {
    [NSTimer scheduledTimerWithTimeInterval:1.0
        target:self
        selector:@selector(timerFired:)
        userInfo:[self userInfo]
        repeat:NO];
}

 

-(void)startRepeatingTimer {
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5
        target:self selector:@selector(timerFired:)
        userInfo:[self userInfo] repeat:YES];
    self.repeatedTimer = timer;
}

타이머의 반복이 없는 경우에는 타이머가 종료된 후 해당 액션을 호출해주고 난 후 타이머는 자체적으로 해제된다. 그렇지 않은 경우에는 추후에 반복되는 타이머를 해제해주기 위해서 따로 참조점을 갖고 있어야 한다.

스케줄링 된 타이머는 생성 즉시 런루프에 추가되어 카운트다운을 시작하게 된다. 이와 별도로 특정 시점부터 동작을 시작하는 타이머는 다음과 같이 만들 수 있다.

-(void)startFireDateTimer {
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:3600];
    NSTimer *timer = [[NSTimer alloc]
        initWithFireDate:fireDate
        interval:0.5
        target:self
        selector:@selector(timerFiredMethod:)
        userInfo:[self uesrInfo]
        repeat:YES];
    NSRunLoop *theRunLoop = [NSRunLoop currentRunLoop];
    [theRunLoop addTimer:timer forMode:NSDefaultRunLoopMode];
}

시작된 타이머를 멈추기

위와 같이 만들어지고 시작된 타이머는 반복되지 않는다면 종료시 호출해야 하는 액션을 호출하고, 정지된다. 하지만 아직 정해진 시간을 다 채우지 않았거나, 반복해서 실행되는 타이머는 멈출 필요도 있다. 타이머를 멈추기 위해서는 해당 타이머에 invalidate 메시지를 보내면 된다.

-(void)stopRepatedTImer
{
    [self.repeatedTimer invalidate];
    self.repeatedTimer = nil;
}

타이머를 사용하지 않은 예약된 작업 호출

타이머를 사용하지 않고도 특정한 시간 지연 후에 간단히 어떤 기능을 실행할 수 있다. 이 기능은 NSObject에 이미 정의된 메소드이다. (역시 코코아의 루트 클래스가 NSObject라는 사실은 매우 다행스럽다!) 이는 -performSelector: withObject : afterDelay: 이다. 이는 다음과 같이 사용할 수 있다.

    
[self.tableView performSelector:@selector(reloadData)
    withObject:nil
    afterDelay:10.0];

이미 예약된 작업 취소하기

NSObject의 클래스 메소드인 +cancelPreviousPerformRequestsWithTarget:selector:object:+cancelPreviousPerformRequestsWithTarget: 을 사용한다. 이는 지연 후에 일을 하게되는 객체가 이 메시지를 받고 예약된 작업을 실행하지 않게 된다.

  • scheduledTimerWithTimeInterval:targer:selector:userInfo:repeats: 를 사용하는 방법이다. 이~

    오타났네요
    targer -> target

    • 수정했습니다. 감사합니다~