2

ブロックについてたくさん知りません。あなたはどのようにしてNSTimerdispatch_after()と偽装しようとしますか?私の問題は、アプリがバックグラウンドに移動するときにタイマーを「一時停止」したいが、サブクラス化するNSTimerは機能していないようだ。iPhone:NSTimerを模倣するためにdispatch_afterを使用する

私はうまくいくものを試しました。私はそのパフォーマンスへの影響や、それが大幅に最適化できるかどうかは判断できません。どんな入力も歓迎です。

#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

私はブロックとバックグラウンドタスクについて自分自身をあまり知らないが、私はあなたのタイマー「一時停止」するために、異なる技術を思うだろう:私はapplicationDidEnterBackgroundを上書きするために残り時間を格納することをお勧め

を(NSTimer'sfireDateに基づいて)、アプリがフォアグラウンドに戻って、applicationWillEnterForegroundが発生した場合は、以前に保存したタイムスタンプに基づいてタイマーを無効にして再計算します。

私はこのソリューションをテストしたが、それはこのことができます:)

+0

私はのUserInfo内の情報を格納することであることを試してみました。しかし、私はあなたがそれを更新できるとは思わない。タイマーオブジェクトの外にそれを格納することはあまり意味がありません。私は別のオブジェクトにタイマーをラップすることができますが、私はそれが非常にエレガントな解決策ではないと思います。まだそれを行うかもしれません... –

+0

タイマー自体の中でその情報を保持したいのであれば、タイマーの 'userInfo'として可変コレクションを使用してみませんか?残りの時間をNSNumberの次の 'fireDate'までラップして、それをタイマーのuserInfoであるコレクションに格納します。 – danyowdee

+1

私は実際にこれを行うカテゴリを作成しました:https://github.com/adamjernst/NSTimer- AbsoluteFireDate –

4

をあなたが[NSDate distantFuture]fireDateを設定することで、単純に「一時停止」バニラNSTimerをも可能性

希望を作業する必要があるようですしていません。あなたのアプリがフォアグラウンドに戻ったとき、あなたは通常のスケジュールを単に再開することができます。

5

ブロックを起動するタイマーの場合は、ディスパッチソースとなります。私は自分のアプリケーションでNSTimerの代わりに何回も使用しましたADCのウェブサイト上の偉大な例があります:

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

+0

ディスパッチソースはこれに最適です。ディスパッチソースを中断して再開することもできます。これはまさにあなたが探しているものです。 –

関連する問題