Question

I am using a sub class in my application, in which i am using nstimer to detect user idle/inactivity. Here is a leak and it raised on every tap. here is code of my class

- (void)sendEvent:(UIEvent *)event {
    [super sendEvent:event];
    isRootView=FALSE;
    // Only want to reset the timer on a Began touch or an Ended touch, to reduce the number of timer resets.
    NSSet *allTouches = [event allTouches];
    if ([allTouches count] > 0) {
        // allTouches count only ever seems to be 1, so anyObject works here.
        UITouchPhase phase = ((UITouch *)[allTouches anyObject]).phase;
        if (phase == UITouchPhaseBegan)
            [self resetIdleTimer];
    }

}

- (void)resetIdleTimer {

    if (idleTimer) 
    {
        if ([idleTimer isValid]) 
        {
            [idleTimer invalidate];
            //[idleTimer release];
            //idleTimer=nil;
        }
    }
    maxIdleTime = 60;
    if (!isRootView) 
    {
        idleTimer = [NSTimer scheduledTimerWithTimeInterval:maxIdleTime target:self selector:@selector(idleTimerExceeded) userInfo:nil repeats:NO];
        [idleTimer retain];
    }
    else {
        if ([idleTimer isValid])
        {
            [idleTimer invalidate];
            //[idleTimer release];
            //idleTimer = nil;
        }
        if ([resetTimer isValid]) {
            [resetTimer invalidate];
            resetTimer=nil;

        }
    }


}

- (void)idleTimerExceeded {

    alert=[[UIAlertView alloc] initWithTitle:@"Confirmation!" message:@"Would you like to continue placing the order ?" delegate:self cancelButtonTitle:@"NO" otherButtonTitles:@"YES", nil];
    alert.tag=100;
    [alert show];
    [alert release];
    resetTimer=[NSTimer scheduledTimerWithTimeInterval:maxIdleTime target:self selector:@selector(resetApplication) userInfo:nil repeats:NO] ;
}
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
    if (alertView.tag==100 ) {
        if (buttonIndex==1) 
        {
            if ([resetTimer isValid]) {
                [resetTimer invalidate];
                resetTimer=nil;

            }
        }
        else {
            [self resetApplication];
        }
    }
}
-(void) resetApplication
{
    isRootView=TRUE;
    [alert dismissWithClickedButtonIndex:1 animated:YES];
    if ([resetTimer isValid]) 
    {
        [resetTimer invalidate];
        resetTimer=nil;
    }

    if (idleTimer)
    {
        [idleTimer invalidate];
        [idleTimer release];
        idleTimer = nil;
    }

    SushiTeriaAppDelegate *appDelegate=(SushiTeriaAppDelegate*)[[UIApplication sharedApplication] delegate];
    [appDelegate resetApp];

}


- (void)dealloc {
    [super dealloc];

    //[resetTimer release];

    [alert release];


}

I have retain this timer. If dont retain then application get crashed.

Please guide me how to remove this leak

shivam

No correct solution

OTHER TIPS

Use assigned property for timer variable. ex.

NSTimer globalTimer;

@property (nonatomic, assigned) NSTimer globalTimer;
@synthesize globalTimer;

Now assign timer on this variable and use like self.globalTimer. One thing is that always assign nil on variable after use. Do not release it another wise it will crashed your application.

What is happening is, you are calling the resetIdleTimer method every time the user taps on the screen. This increases the retain count of the idleTimer every time because you have retained it. The reason your app crashes if you don't retain is because you get an autoreleased NSTimer object from NSTimer class method

idleTimer=[NSTimer scheduledTimerWithTimeInterval:maxIdleTime target:self selector:@selector(idleTimerExceeded) userInfo:nil repeats:NO];

This means that you cannot use this object outside that particular method as you do in your resetApplication method. Now you could check the retain count every time you retain it but that is a hassle. So what I suggest is you declare idleTimer as a retain property.

@property (retain) NSTimer *idleTimer;

and synthesize its setters and getters after implementation.

@synthesize idleTimer;

now use

self.idleTimer=[NSTimer scheduledTimerWithTimeInterval:maxIdleTime target:self selector:@selector(idleTimerExceeded) userInfo:nil repeats:NO];

and release idleTimer only in your dealloc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top