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?
In Objective-C, a primitive type is not an object. So you can't directly pass it to an argument which expects an
id
, which stands for a generic object. You need to wrap it into anNSNumber
object.Use
and
Don't forget to invalidate and release the timer once it's done.
By the way, you don't have to compare a
BOOL
(or C++bool
) againstYES
ortrue
or whatever. When you writea>b
evaluates to a bool, andif
uses the result. What you're doing there is likewhich is quite strange to me. It's not that the
(..)
afterif
should contain a comparison; it should contain a bool.As a follow-up to kperryua's answer, if you want to pass a primitive through userInfo you can box it with
NSNumber
orNSValue
; in the case of a boolean, you'd want to use[NSNumber numberWithBool:YES]
, then callboolValue
in the timer callback to get back the primitive.The
userInfo
parameter must be an object; it is typedid
.YES
is a primitive, namely the value1
. In order to make sure theuserInfo
object does not get deallocated, the timer retains it. So, when you passedYES
, NSTimer was doing[(id)YES retain]
. Try that in your own code and see what happens. :-PAs the Documentation states, the selector you give the method must have the signature
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 itYES
. You can do this like so: