iphone多次NSTimer麻烦

时间:2009-10-18 01:24:38

标签: iphone object nstimer

我仍然是编程的新手,所以如果这很愚蠢,请原谅。我正在编写一个简单的游戏,并且需要多个计时器以不同的间隔发送不同的消息,因此在创建游戏时,会调用以下内容:

[self gameTimerValidate];
[self scoreTimerValidate];

- (void) gameTimerValidate
{
gameTimer = [NSTimer scheduledTimerWithTimeInterval:[myGame gIntervalSpeed] target:self selector:@selector(gameTimerInterval:) userInfo:nil repeats:YES];
}

- (void) scoreTimerValidate
{
scoreTimer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(scoreTimerInterval:) userInfo:nil repeats:YES];
}

我在我的头文件(“NSTimer * gameTimer;”)中声明了scoreTimer和gameTimer。暂停游戏或完成关卡时,我使计时器无效,并在恢复游戏或进入下一关卡时再次调用上述方法。

今天我花了几个小时试图找出暂停游戏会导致应用程序崩溃的原因。做了一些调试之后,我注意到gametimer的保留计数为0,而得分记录为2.当然,我不能使保留计数为0的计时器无效,但我不确定是怎么发生的。< / p>

我必须以特定的方式初始化两个不同的NStimers吗?我一直在寻找数小时无济于事......

5 个答案:

答案 0 :(得分:4)

NSTimer是一个棘手的课程。它的行为并不像你期望的那样。

首先,初始化它们的对象最终不会保留定时器实例,而是由IIRC(NSRunLoop)保留。这意味着如果您有一个创建计时器的对象,即使您销毁了创建它的对象和自定义代码中的所有其他引用,计时器也将继续处于活动状态。计时器将继续发射消息,你不知道他们来自哪里。

其次,您无法停止/暂停和恢复计时器。当你使它失效时,它已经死了。

我建议创建一个轻量级,为您管理计时器,这样您就不必在其余代码中跟踪它。 e.g。

@interface SDL_SimpleTimerController : NSObject {
    NSTimer *currentTimer;
    NSTimeInterval theInterval;
    id theTargetObj;
    SEL theSelector;

    BOOL timerIsRunning;
}
@property (nonatomic,retain) NSTimer *currentTimer;
@property NSTimeInterval theInterval;
@property (nonatomic,retain) id theTargetObj;
@property SEL theSelector;
@property BOOL timerIsRunning;

-(SDL_SimpleTimerController *) initWithInterval:(NSTimeInterval)anInterval forTarget:(id)aTargetObj andSelector:(SEL)aSelector;

-(void) startTimer;
-(void) stopTimer;                                  
@end

@implementation SDL_SimpleTimerController
@synthesize currentTimer;
@synthesize theInterval;
@synthesize theTargetObj;
@synthesize theSelector;
@synthesize timerIsRunning;

-(SDL_SimpleTimerController *) initWithInterval:(NSTimeInterval) anInterval forTarget:(id) aTargetObj andSelector:(SEL) aSelector
{
    self=[super init];
    theInterval=anInterval;
    theTargetObj=aTargetObj;
    theSelector=aSelector;
    timerIsRunning=NO;

    return self;

}// end initWithInterval:   


-(void) startTimer{
    if (currentTimer) { 
        currentTimer=Nil;
    }
    currentTimer=[NSTimer scheduledTimerWithTimeInterval:theInterval  target:theTargetObj selector:theSelector userInfo:Nil repeats:YES];
    timerIsRunning=YES;
}//end startTimer

-(void) stopTimer{
    if (currentTimer) {
        [currentTimer invalidate];
        currentTimer=Nil;
    }
    timerIsRunning=NO;
}// end stopTimer

- (void)dealloc { 
    if (currentTimer) {
        [currentTimer release];
        currentTimer=Nil;
    }
    [theTargetObj release];
    theTargetObj=Nil;
    [super dealloc];
}

答案 1 :(得分:2)

计时器不可重复使用。使它们失效后,它们将从运行循环中删除,并且它们的保留计数会减少,从而导致下次循环时释放它们。您要么必须创建新的,要么停止使它们失效。

答案 2 :(得分:0)

我认为您应该尝试找到您可能正在进行[scoreTimer保留]的位置,以及您可能多次无效(或释放)gameTimer的位置(您只需要执行后者,如果您检查了retainCount) ,是你曾经失效一次之后)。您无法通过调用

之一来增加retainCount
[self gameTimerValidate];
[self scoreTimerValidate];
不止一次。你会泄漏内存,并且有两个定时器以相同的间隔触发,但你不会因为这个原因而使其中一个定时器具有更高的retainCount。

如果这两个实例变量是保留属性,并且您使用self.gameTimer = ...设置它们,那么我可以看到它们保留了额外的时间。但是我看到的代码并没有解释你的问题。

搜索这两个计时器的所有实例,看看还有什么可能搞乱了。

一个建议,你可能想要检查nil,如下:

- (void) gameTimerValidate
{
    if (gameTimer == nil)
        gameTimer = [NSTimer scheduledTimerWithTimeInterval:[myGame gIntervalSpeed] target:self selector:@selector(gameTimerInterval:) userInfo:nil repeats:YES];
}

- (void) scoreTimerValidate
{
    if (scoreTimer == nil)
        scoreTimer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(scoreTimerInterval:) userInfo:nil repeats:YES];
}
- (void) invalidateMyTimers {
    [gameTimer invalidate], gameTimer = nil;
    [scoreTimer invalidate], scoreTimer = nil;
}

答案 3 :(得分:0)

感谢回复,在给出一些想法之后我会采用类似于TechZen所说的方法,并且只是让计时器运行BOOL变量,并使用该变量来检查诸如暂停和这样(即改变布尔值与停止和启动定时器)。

(也是我第一次使用这个网站,仍在学习答案的格式)再次感谢!

答案 4 :(得分:0)

在回复TechZen的灯光类时,我认为你不应该发布上面的目标对象,因为你没有创建它(因此不拥有它)

 (void)dealloc { 
if (currentTimer) {
    [currentTimer release];
    currentTimer=Nil;
}
**[theTargetObj release];**
theTargetObj=Nil;
[super dealloc];

}