【问题标题】:Countdown timer using NSTimer in "0:00" format使用“0:00”格式的 NSTimer 倒数计时器
【发布时间】:2011-03-18 00:10:15
【问题描述】:

我这几天一直在研究如何做到这一点,但没有人给出答案。

我正在同一视图上创建一个包含 5 个计时器的应用。 我需要创建一个从“15:00”(分钟和秒)开始倒计时的计时器,以及另一个从“2:58”(分钟和秒)开始倒计时的计时器。 15 分钟计时器不应重复,但应在到达“00:00”时停止所有其他计时器。 “2:58”计时器应该重复,直到“15:00”或“游戏时钟”达到 0。现在,我已经废弃了几乎所有的代码,我正在研究“2:58”重复计时器,或“火箭计时器”。

有人知道怎么做吗?

编辑 2: 我的模拟器甚至不会运行该应用程序,所以我目前不知道计时器是否真的在工作,但从我之前的尝试来看,它没有工作。它没有以我想要的格式显示,并且按 2 倒计时(从它最后一次实际工作开始)。问题还在于,我对 Objective-C 并不流利。我可以整天写伪代码,就像其他人一样,但我不能把我想要的东西写进代码,因为我不完全理解 NSTimer。

编辑:

在我的输出中,我收到此错误“在抛出 'NSException' 实例后调用终止”

这个错误?

这是我的代码:

    #import <UIKit/UIKit.h>


@interface FirstViewController : UIViewController {



    //Rocket Timer
    int totalSeconds;
    bool timerActive;
    NSTimer *rocketTimer;
    IBOutlet UILabel *rocketCount;

    int newTotalSeconds;
    int totalRocketSeconds;
    int minutes;
    int seconds;

}

- (IBAction)Start;



@end

还有我的.m

    #import "FirstViewController.h"

@implementation FirstViewController

- (NSString *)timeFormatted:(int)newTotalSeconds
{

    int seconds = totalSeconds % 60; 
    int minutes = (totalSeconds / 60) % 60; 


    return [NSString stringWithFormat:@"%i:%02d"], minutes, seconds; 
}


-(IBAction)Start {

    newTotalSeconds = 178; //for 2:58

    newTotalSeconds = newTotalSeconds-1;

    rocketCount.text = [self timeFormatted:newTotalSeconds];


    if(timerActive == NO){

        timerActive = YES;
        newTotalSeconds = 178;

      [rocketTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerLoop) userInfo:nil repeats:YES];
    }

    else{

        timerActive = NO;
        [rocketTimer invalidate];
        rocketTimer = nil;

    }

}



-(void)timerLoop:(id)sender {

    totalSeconds = totalSeconds-1;

    rocketCount.text = [self timeFormatted:totalSeconds];


}

- (void)dealloc
{
    [super dealloc];

    [rocketTimer release];


}

- (void)didReceiveMemoryWarning
{
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    // Release any cached data, images, etc that aren't in use.
}


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    timerActive = NO;
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end

【问题讨论】:

  • 你取得了什么成就,什么没有?从我在这里看到的,它应该正确更新标签。可以?还是它没有重复的问题?

标签: objective-c cocoa-touch nstimer countdown


【解决方案1】:

您的代码存在一些问题!
坏消息是,它们都与您看到的崩溃无关。

第一个也是最明显的问题

实际上,你永远不会停止倒计时!

Start 中安排计时器后,您的timerLoop: 方法将每秒调用一次。但是你忘了检查totalSeconds是否变成负数了……

第二个问题

-(NSString *)timeFormatted:(int)newTotalSeconds 不会像您期望的那样工作!实际上,我非常确定 Xcode 会给你一个编译器警告,说明 “'newTotalSeconds' 的本地声明隐藏了实例变量”
试试看:在Start 中,将rocketCount.text = [self timeFormatted:newTotalSeconds]; 行替换为rocketCount.text = [self timeFormatted:42]; 行并在其后设置断点。

第三个问题(实际上是一个地方的几个问题)

您的dealloc 完全错误:
首先,在[super dealloc] 之后拨打电话并不是最好的主意。第二,“你做错了”:考虑到你的Start-方法,你不拥有计时器,所以你不能release它。相反,如果计时器仍然有效,您需要 invalidate 它。但这甚至不会成为问题,因为只要安排了rocketTimer,您的viewController 就不会是dealloced(除非您在其他地方的内存管理中有错误)。我已经写了fairly complete example 在之前的帖子中解释了这种行为。

那么,导致崩溃的原因是什么?

老实说:
没有线索!

为了找出究竟出了什么问题,请尝试向-[NSException raise] 添加断点。或者,您可以将main.m 中的main 函数修改为以下内容:

int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    int response;
    @try {
        response = UIApplicationMain(argc, argv, nil, nil);
    } @catch (NSException *e) {
        NSLog(@"%@: %@\nCall-stack:\n%@", [e name], [e reason], [e callStackSymbols]);
        response = 1;
    }
    return response;
}

这将告诉您您的程序实际崩溃的方法。

【讨论】:

  • 维护小时:分钟:秒计时器文本的完美答案。
【解决方案2】:

rocketTimer 在哪里实例化?你似乎遗漏了那个非常重要的细节。我的猜测是 rocketTimer 没有被您的代码正确保留,这会导致您在释放该对象后尝试访问该对象时崩溃。

我建议合成您的属性,然后在初始化时通过设置self.rocketTimer 来使用内置设置。

FirstViewController.h

@interface FirstViewController : UIViewController {
    NSTimer *rocketTimer;
}
@property (nonatomic, retain) NSTimer *rocketTimer;
- (IBAction)Start;
@end

FirstViewController.m

@implementation FirstViewController
@synthesize rocketTimer;
// test of implementation
// ...

【讨论】:

  • 另外,请在您的交易中最后调用[super dealloc]
  • “rocketTimer 实例化在哪里?你似乎遗漏了那个非常重要的细节”不,他没有。它在他的Start-method 的 if 子句的最后一行被实例化。
  • @danyowdee 是的,错过了那条线。在任何情况下,计时器都没有正确保留。
  • 它不需要:计时器在运行循环上重复和调度——retains the timer(参见第 2 句第 2 段)直到调用invalidate
【解决方案3】:

如果问题在于它没有重复,我会让 timerLoop 方法在减法之前检查 totalSeconds 的值。如果它是 0,让它再次设置为 178。

如果问题出在其他地方,请告诉我们在哪里,并提供更多信息,说明问题是什么以及您下次已经尝试过什么。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-24
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多