iPhone:使用dispatch_after来模仿NSTimer

时间:2011-01-17 15:46:14

标签: objective-c nstimer objective-c-blocks grand-central-dispatch invocation

不知道很多关于积木的事情。您将如何使用NSTimer模仿重复的dispatch_after()?我的问题是,当应用程序移动到后台时我想“暂停”一个计时器,但子类化NSTimer似乎不起作用。

我尝试过似乎有用的东西。我无法判断其性能影响或是否可以大大优化。欢迎任何意见。

#import "TimerWithPause.h"


@implementation TimerWithPause

@synthesize timeInterval;
@synthesize userInfo;
@synthesize invalid;
@synthesize invocation;

+ (TimerWithPause *)scheduledTimerWithTimeInterval:(NSTimeInterval)aTimeInterval target:(id)aTarget selector:(SEL)aSelector userInfo:(id)aUserInfo repeats:(BOOL)aTimerRepeats {

    TimerWithPause *timer = [[[TimerWithPause alloc] init] autorelease];

    timer.timeInterval  = aTimeInterval;

    NSMethodSignature *signature = [[aTarget class] instanceMethodSignatureForSelector:aSelector];
    NSInvocation *aInvocation = [NSInvocation invocationWithMethodSignature:signature];
    [aInvocation setSelector:aSelector];
    [aInvocation setTarget:aTarget];
    [aInvocation setArgument:&timer atIndex:2];
    timer.invocation = aInvocation;

    timer.userInfo      = aUserInfo;

    if (!aTimerRepeats) {
        timer.invalid = YES;
    }

    [timer fireAfterDelay];

    return timer;
}

- (void)fireAfterDelay {

    dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, self.timeInterval * NSEC_PER_SEC);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_after(delay, queue, ^{

        [invocation performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:NO];

        if (!invalid) {         
            [self fireAfterDelay];
        }
    });
}

- (void)invalidate {
    invalid = YES;

    [invocation release];
    invocation = nil;

    [userInfo release];
    userInfo = nil;
}

- (void)dealloc {

    [self invalidate];

    [super dealloc];
}

@end

3 个答案:

答案 0 :(得分:5)

因此,对于您想要触发一个块的计时器,您需要一个调度源。 ADC网站上有一个很好的例子,我在我的应用程序中多次使用NSTimer代替:

http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/GCDWorkQueues/GCDWorkQueues.html%23//apple_ref/doc/uid/TP40008091-CH103-SW2

答案 1 :(得分:4)

您也可以通过将NSTimer设置为fireDate来“暂停”一个香草[NSDate distantFuture]。当您的应用程序返回到前台时,您可以简单地恢复正常的计划。

答案 2 :(得分:3)

我对块和后台任务我不太了解,但我会想到一种不同的技术来“暂停”你的计时器:

我建议覆盖applicationDidEnterBackground并存储计时器的剩余时间(基于NSTimer's fireDate),然后当应用返回前台时applicationWillEnterForeground根据您之前保存的时间戳触发,失效并重新计算您的计时器。

我没有测试过这个解决方案,但似乎它应该正常工作

希望这会有所帮助:)