Search code examples
objective-ccocoacocoa-touchnstimer

Proper way of passing a primitive argument with an NSTimer


I'm using a basic timer that calls this method:

- (void) refresh:(id)obj
{
    if (obj == YES) doSomething;
}

I want to call this method from certain areas of my code and also from a timer

[NSTimer scheduledTimerWithTimeInterval:refreshInterval
                            target:self
                            selector:@selector(refresh:) 
                            userInfo:nil 
                            repeats:YES];

When I put YES as the argument for the userInfo parameter, I get an EXC_BAD_ACCESS error; why is this?

Can someone help me do this the right way so that there is no ugly casting and such?


Solution

  • The userInfo parameter must be an object; it is typed id. YES is a primitive, namely the value 1. In order to make sure the userInfo object does not get deallocated, the timer retains it. So, when you passed YES, NSTimer was doing [(id)YES retain]. Try that in your own code and see what happens. :-P

    As the Documentation states, the selector you give the method must have the signature

    - (void)timerFireMethod:(NSTimer*)theTimer
    

    This means you can't have an NSTimer invoke just any method—not directly at least. You can make a special method with the above signature which in turn invokes any method you want though.

    So, say you have a method called refresh:, and you want to call it every so often, passing it YES. You can do this like so:

    // somewhere
    {
        [NSTimer scheduledTimerWithTimeInterval:refreshInterval
                                         target:self
                                       selector:@selector(invokeRefresh:)
                                       userInfo:nil
                                        repeats:YES];
    }
    
    - (void)invokeRefresh:(NSTimer *)timer {
        [self refresh:YES];
    }
    
    - (void)refresh:(BOOL)flag {
        if (flag) {
            // do something
        }
    }