2

Ich weiß nicht viel über Blöcke. Wie würden Sie eine wiederholte NSTimer mit dispatch_after() imitieren? Mein Problem ist, dass ich einen Timer "pausieren" möchte, wenn die App in den Hintergrund bewegt, aber Unterklasse NSTimer scheint nicht zu funktionieren.iPhone: Verwenden von dispatch_after, um NSTimer zu imitieren

Ich habe etwas versucht, das zu funktionieren scheint. Ich kann seine Auswirkungen auf die Leistung nicht beurteilen, oder ob sie stark optimiert werden könnten. Jede Eingabe ist willkommen.

#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 

Antwort

3

Ich weiß nicht viel über mich Blöcke und Hintergrundaufgaben, aber ich würde eine andere Technik denken „Pause“, um Ihre Timer:

würde ich vorschlagen applicationDidEnterBackground und zu speichern, die Zeit zu überschreiben ist noch Zeit der Timer (basierend auf NSTimer'sfireDate), dann, wenn die App wieder im Vordergrund ist und applicationWillEnterForeground ausgelöst wird, ungültig und neu berechnen Sie Ihre Timer auf der Grundlage der Zeitstempel, die Sie zuvor gespeichert haben.

ich diese Lösung nicht getestet haben, scheint aber sollte es

Hoffnung arbeiten, das hilft :)

+0

Ich habe versucht, dass durch die Informationen innerhalb userinfo speichern. Aber ich denke nicht, dass du das aktualisieren kannst. Es außerhalb des Timer-Objekts zu speichern macht wenig Sinn. Ich könnte den Timer in ein anderes Objekt einpacken, aber ich denke nicht, dass das eine sehr elegante Lösung ist. Kann das immer noch tun ... –

+0

Wenn Sie diese Informationen innerhalb des Timers persistieren möchten, warum verwenden Sie nicht eine veränderbare Sammlung als 'userInfo' des Timers? Wickle die verbleibende Zeit bis zum nächsten 'fireDate' in einer NSNumber und speichere sie in der Sammlung, die die userInfo des Timers ist ... – danyowdee

+1

Ich habe tatsächlich eine Kategorie erstellt, die genau das tut: https://github.com/adamjernst/NSTimer- AbsoluteFireDate –

4

Sie könnten auch einfach „Pause“ ein Vanille NSTimer durch die fireDate-[NSDate distantFuture] Einstellung. Wenn Ihre App wieder in den Vordergrund kommt, können Sie einfach den normalen Zeitplan fortsetzen.

5

Also für Timer, die Sie einen Block auslösen möchten, würden Sie eine Versandquelle. Es ist ein großartiges Beispiel auf der ADC-Website, die ich oft an Stelle von NSTimer in meiner Apps verwendet habe:

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

+0

Versandquellen sind dafür perfekt geeignet. Sie können sogar eine Versandquelle anhalten und fortsetzen, was genau das ist, was Sie tun möchten. –

Verwandte Themen