iphone多个NSTimer故障

iphone多个NSTimer故障,iphone,object,nstimer,Iphone,Object,Nstimer,我对编程还是新手,所以如果这很愚蠢,请原谅。我正在编写一个简单的游戏,需要多个计时器以不同的时间间隔发送不同的消息,因此在创建游戏时,调用以下命令: [self gameTimerValidate]; [self scoreTimerValidate]; - (void) gameTimerValidate { gameTimer = [NSTimer scheduledTimerWithTimeInterval:[myGame gIntervalSpeed] target:self sele

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

[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,而scoretimer的保留计数为2。当然,我不能使保留计数为0的计时器无效,但我不确定这是如何发生的


是否有一种特定的方法必须初始化两个不同的NSTimer?我在这上面搜索了几个小时都没有用…

计时器不可重复使用。在使它们无效后,它们将从运行循环中删除,并且它们的保留计数将减少,从而导致它们在下次通过循环时取消分配。您必须创建新计时器或停止使其无效。

计时器不可重复使用。在使它们无效后,它们将从运行循环中删除,并且它们的保留计数将减少,从而导致它们在下次通过循环时取消分配。您必须创建新的或停止使其无效。

我认为您应该尝试找到您可能在哪里执行[scoreTimer retain],以及您可能在哪里多次使gameTimer无效(或释放)gameTimer(如果您检查了retainCount,并且是在您已使其无效一次之后,您只需要执行后者)。您不能通过调用以下任何一项来增加重新计数

[self gameTimerValidate];
[self scoreTimerValidate];
不止一次。您可能会泄漏内存,并且有两个计时器以相同的时间间隔触发,但您不会让其中一个计时器因此具有更高的重新计数

如果这两个实例变量是保留属性,并且您使用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;
}

我认为你应该试着找出你可能在哪里做[scoreTimer retain],以及你可能在哪里多次使gameTimer失效(或释放)gameTimer(如果你在失效一次之后检查了retainCount,你只需要做后者)。您不能通过调用以下任何一项来增加重新计数

[self gameTimerValidate];
[self scoreTimerValidate];
不止一次。您可能会泄漏内存,并且有两个计时器以相同的时间间隔触发,但您不会让其中一个计时器因此具有更高的重新计数

如果这两个实例变量是保留属性,并且您使用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;
}

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

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

其次,你不能停止/暂停并恢复计时器。当你宣布它无效时,它就死了

我建议创建一个轻量级的类来为您管理计时器,这样您就不必在代码的其余部分跟踪它。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];
}

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

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

其次,你不能停止/暂停并恢复计时器。当你宣布它无效时,它就死了

我建议创建一个轻量级的类来为您管理计时器,这样您就不必在代码的其余部分跟踪它。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];
}

感谢您的回复,在考虑之后,我将采用与TechZen所说的类似的方法,使用BOOL变量保持计时器运行,并使用该变量检查暂停等事件(即更改布尔值与停止和启动计时器)


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

感谢您的回复,在考虑之后,我将采用类似TechZen所说的方法,使用BOOL变量保持计时器运行,并使用该变量检查暂停等事件(即更改布尔值vs停止和启动计时器)


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

对于TechZen的light类,我认为您不应该释放上面的目标对象,因为您没有创建它(因此不拥有它)


}

作为对TechZen的light类的回复,我认为您不应该释放上面的目标对象,因为您没有创建它(因此不拥有它)

}