2010-07-10 42 views
3

所以我試圖建立一個基本的計時器,但我失敗悲慘。基本上我想要的是當用戶點擊一個按鈕時啓動一個60秒的定時器,並用剩餘時間更新標籤(如倒計時)。我創建了我的標籤和按鈕,並將它們連接到IB。接下來,我爲該按鈕創建了一個IBAction。現在,當我嘗試更新基於計時器的標籤時,我的應用程序被鎖定了。這裏是我的代碼:NSTimer問題

NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 1 
         target: self 
         selector:@selector(updateLabelDisplay) 
         userInfo: nil repeats:YES]; 

我也有決定多少次計時器已經跑了,然後減去這個數字爲60,顯示在倒計時標籤,該標籤數量updateLabelDisplay功能。誰能告訴我我做錯了什麼?

+0

您可以擴展「我的應用程序擰緊?」。你能觀察到什麼發生了? – 2010-07-10 20:19:27

+0

此外,根據您的描述,聽起來您有一個下限(從60開始倒計時),所以想必您會在某個時間點使計時器無效。雖然這不是你的問題,但你稍後會想要引用計時器來使其失效。也許你稍後會在代碼中做這件事,但由於你最初使用了一個局部變量,所以我認爲值得一提的是稍後爲你節省頭痛。 – 2010-07-10 20:26:36

+0

基本上標籤不會更新。 – Roosh 2010-07-10 20:41:50

回答

11

好吧,那麼對於初學者,檢查了這一點,如果你還沒有準備好:Official Apple Docs about Using Timers

根據您的描述,您可能需要的代碼看起來是這樣的。我對行爲做了一些假設,但你可以適應口味。

這個例子假定你想要保持對定時器的引用,以便你可以暫停它或某事。如果不是這種情況,可以修改handleTimerTick方法,以便它將NSTimer *作爲參數,並在計時器過期後使用它來使其失效。

@interface MyController : UIViewController 
{ 
    UILabel * theLabel; 

    @private 
    NSTimer * countdownTimer; 
    NSUInteger remainingTicks; 
} 

@property (nonatomic, retain) IBOutlet UILabel * theLabel; 

-(IBAction)doCountdown: (id)sender; 

-(void)handleTimerTick; 

-(void)updateLabel; 

@end 

@implementation MyController 
@synthesize theLabel; 

// { your own lifecycle code here.... } 

-(IBAction)doCountdown: (id)sender 
{ 
    if (countdownTimer) 
    return; 


    remainingTicks = 60; 
    [self updateLabel]; 

    countdownTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: @selector(handleTimerTick) userInfo: nil repeats: YES]; 
} 

-(void)handleTimerTick 
{ 
    remainingTicks--; 
    [self updateLabel]; 

    if (remainingTicks <= 0) { 
    [countdownTimer invalidate]; 
    countdownTimer = nil; 
    } 
} 

-(void)updateLabel 
{ 
    theLabel.text = [[NSNumber numberWithUnsignedInt: remainingTicks] stringValue]; 
} 


@end 
+3

值得注意的是,這樣做的更好方法是使用時間間隔根據經過的時間更新標籤,而不是依賴滴答計數器。由於runloops的特性,您無法保證計時器觸發時的精度。但上面的代碼很好。 – 2010-07-10 21:08:50

+0

非常感謝!只有一個問題,doCountdown將連接到我的UIButton是否正確? – Roosh 2010-07-10 21:33:01

+0

這是正確的。 doCountdown:是連接到你的按鈕的動作。 – 2010-07-10 21:40:57

1

它可能是一個有點晚後第二個回答這個問題,但我一直在尋找一個好地方後我自己解決這個問題。如果它對任何人都有用,它就是這樣。它發射8次,但當然這可以根據你的需要定製。計時器在時間到了時解除分配。

我喜歡這種方法,因爲它使計數器與計時器集成在一起。

要創建一個實例調用是這樣的:

SpecialKTimer *timer = [[SpecialKTimer alloc] initWithTimeInterval:0.1 
                 andTarget:myObject 
                 andSelector:@selector(methodInMyObjectForTimer)]; 

無論如何,這裏是頭部和方法文件。

//Header 

#import <Foundation/Foundation.h> 

@interface SpecialKTimer : NSObject { 

    @private 

    NSTimer *timer; 

    id target; 
    SEL selector; 

    unsigned int counter; 

} 

- (id)initWithTimeInterval:(NSTimeInterval)seconds 
       andTarget:(id)t 
       andSelector:(SEL)s; 
- (void)dealloc; 

@end 

//Implementation 

#import "SpecialKTimer.h" 

@interface SpecialKTimer() 

- (void)resetCounter; 
- (void)incrementCounter; 
- (void)targetMethod; 

@end 

@implementation SpecialKTimer 

- (id)initWithTimeInterval:(NSTimeInterval)seconds 
       andTarget:(id)t 
       andSelector:(SEL)s { 

    if (self == [super init]) { 

     [self resetCounter]; 

     target = t; 
     selector = s; 

     timer = [NSTimer scheduledTimerWithTimeInterval:seconds 
               target:self 
               selector:@selector(targetMethod) 
               userInfo:nil 
               repeats:YES]; 

    } 

    return self; 

} 

- (void)resetCounter { 

    counter = 0; 

} 

- (void)incrementCounter { 

    counter++; 

} 

- (void)targetMethod { 

    if (counter < 8) { 

     IMP methodPointer = [target methodForSelector:selector]; 
     methodPointer(target, selector); 

     [self incrementCounter]; 

    } 

    else { 

     [timer invalidate]; 
     [self release]; 

    } 

} 

- (void)dealloc { 

    [super dealloc]; 

} 

@end 
+0

對自己調用'-dealloc'是不好的。見http://stackoverflow.com/questions/3819603/suicide-objective-c-objects-calling-their-own-dealloc-methods-on-the- their。 – SK9 2010-09-29 10:47:45