Search code examples
iosobjective-cnstimer

NSTimer userInfo Bad Access exception


I got a problem with the NSTimer and the userInfo.
In the docs Apple writes that the system keeps a strong reference to the Timer (and therefore the userInfo?) though sometimes when I'm trying to access parts of the userInfo object I'm getting a Bad Access exception. (Afaik that means something really bad happened)

Without further ado, here's how my object looks like that I pass to the userInfo:

@interface MyObject

@property (nonatomic, assign) u_int8_t cmd;
@property (nonatomic, assign) NSNumber *_id;

@end

And here's how I set the Timer:

NSTimer *myTimer = [NSTimer timerWithTimeInterval:10 target:self selector:@selector(someMethod:) userInfo:message repeats:NO];
[[NSRunLoop mainRunLoop] myTimer forMode:NSDefaultRunLoopMode];

The method that gets triggered when the Timer fires

-(void) someMethod:(NSTimer *)timer{
    MyObject* mObject = [timer userInfo];
    u_int8_t cmd = mObject.cmd; // This works
    NSNumber *_id = mObject._id; // Bad access
}

Note: The userInfo itself isn't nil. Neither is the u_int8_t nil or whatsoever. But as soon as I try to access the NSNumber object I'm receiving the following exception (not necessarily every time):

Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x00000000

What happens if I add a strong property to the NSNumber object? Would this fix the issue and why? Why does this problem happen in the first place?


Solution

  • As NSNumber is an object you need to use the strong attribute, which is the default, so change the @property declaration to:

    @property (nonatomic) NSNumber *_id;
    

    And using _id as the identifier is a bad idea as id is an Objective-C keyword, and you will likely confuse yourself at some point.