will this cause memory leak?

Discussion in 'Mac Programming' started by Darkroom, Jul 6, 2008.

  1. Darkroom Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #1
    i'm recently researching ways to disable dimming, screen saver and sleep while an app is in full screen, and this is what i've discovered:

    Code:
    - (void)preventSleep
    {
         keepAwakeTimer = [[NSTimer scheduledTimerWithTimeInterval:30  
    target:self selector:@selector(stayAwake:) userInfo:nil repeats:  
    YES] retain];
    }
    - (void)stayAwake:(NSTimer *)sleepTimer
    {
        UpdateSystemActivity(OverallAct);// This is from Apple Tech Note  
    QA1160:Preventing Sleep
    }
    
    i've noticed that the keepAwakeTimer is retained, and will fire off ever 30 seconds... does that mean that every 30 second the app will allocate memory without releasing it?
     
  2. Sayer macrumors 6502a

    Sayer

    Joined:
    Jan 4, 2002
    Location:
    Austin, TX
    #2
    There's a better way than running a timer every 30 seconds.

    You should register for Power Management events and when the system wants to go to sleep you simply deny it. This way your app isn't constantly running wasting CPU time or potentially leaking memory.

    Here's what I did (note this is in the main.m file):

    Code:
    #import <Cocoa/Cocoa.h>
    #import <mach/mach_port.h>
    #import <mach/mach_interface.h>
    #import <mach/mach_init.h>
    
    #import <IOKit/pwr_mgt/IOPMLib.h>
    #import <IOKit/IOMessage.h>
    
    io_connect_t		root_port;
    IONotificationPortRef	notify;
    io_object_t 		anIterator;
    
    void callback(void * x,io_service_t y,natural_t messageType,void * messageArgument)
    {
        printf("messageType %08lx, arg %08lx\n",(long unsigned int)messageType, (long unsigned int)messageArgument);
        
        switch ( messageType ) {
        case kIOMessageSystemWillSleep:
            IOAllowPowerChange(root_port,(long)messageArgument);
            printf("Going to sleep now\n");
            break;
        case kIOMessageCanSystemSleep: // we don't want to automatically go to sleep
            IOCancelPowerChange(root_port,(long)messageArgument);
            break;
        case kIOMessageSystemHasPoweredOn:
            printf("Just had a nice snooze\n");
            break;
    	default:
    		break;
        }
        
    } /* callback */
    
    int main(int argc, char *argv[])
    {
    
    
        fprintf(stderr, "\nAttempting to register for system power notifications\n");
        root_port = IORegisterForSystemPower (0,&notify,callback,&anIterator);
        if ( root_port == MACH_PORT_NULL ) {
                fprintf(stderr, "IORegisterForSystemPower failed\n");
                return 1;
        }
            fprintf(stderr, "Registration successful\n");
        
        CFRunLoopAddSource(CFRunLoopGetCurrent(),
                            IONotificationPortGetRunLoopSource(notify),
                            kCFRunLoopDefaultMode);
    	
        return NSApplicationMain(argc, (const char **) argv);
    }
    
    void closeIOKit() {
    
    	kern_return_t result;
    	
    	result = IODeregisterForSystemPower(&anIterator);
    	IOServiceClose(root_port);
    	IOObjectRelease(anIterator);
    	
    	if (result == kIOReturnSuccess )
    		fprintf(stderr, "Deregistration successful\n");
    
    }
    Note that with this code the system will go to sleep if the user explicitly tells it to e.g. presses the power button or selects any Sleep option in the UI.

    There really isn't any way to cancel the user telling the system to go to sleep except maybe with the Kiosk APIs and/or disabling key combos/menus.

    To properly close down the Mach port on app quit I use this in the app controller class:

    Code:
    - (void)applicationWillTerminate:(NSNotification *)notification {
    
    	[self adShowExitFullScreenMode];
    
    	closeIOKit();
    }
     
  3. Darkroom thread starter Guest

    Darkroom

    Joined:
    Dec 15, 2006
    Location:
    Montréal, Canada
    #3
    does this also disable dimming and screen saver activity?
     
  4. kpua macrumors 6502

    Joined:
    Jul 25, 2006
    #4
    While the above reply is a better solution for what you want to do, to answer your original question, the answer is yes UNLESS you invalidate/release the timer at some point (i.e. app termination). Of course, leaks at the end of the app's life are not a huge deal, since the OS reclaims the memory anyway, but it's still good practice to eliminate those kind of leaks as well.
     
  5. luckylefty01 macrumors member

    Joined:
    Apr 8, 2008
    #5
    I think the question is how often you're calling the preventSleep method. I'm guessing you're calling that method only once, after which you just call the keepAwakeTimer method when you need it. In that case keepAwakeTimer should only be retained once (when you call preventSleep). If you do call -preventSleep more than once that you need to make sure to release the current instance of keepAwakeTime before assigning the new one.

    And then you should call [keepAwakeTimer release] in dealloc.

    One way to test this would be to set a breakpoint on the line with retain and see how many times that line gets hit.
     

Share This Page