Owen Zhao
Owen Zhao

Reputation: 3355

NSNumber cause app crash

I have a @property opacity in .h file

@property (assign) NSNumber *opacity;

Then in .m file I

@synthesize opacity;

Then in

- (id)initWithFrame:(NSRect)frame

I did

 opacity = [NSNumber numberWithFloat:1.0];

When I run the app, Xcode shows this error

Thread 1: EXC_BAD_ACCESS (code-EXC_I386_GPFLT)

However, if I change that line to

opacity = [NSNumber numberWithInteger:1];

Everything works fine.

Upvotes: 2

Views: 771

Answers (1)

Matthias Bauch
Matthias Bauch

Reputation: 90117

It just looks like it works fine. But you have just covered that bug with an implementation detail of NSNumber.

As Volker pointed out you have a memory management problem. Your property should use strong. As in:

@property (strong) NSNumber *opacity;

And you should use that property when assigning values. e.g.:

self.opacity = [NSNumber numberWithFloat:1.0];

So why does it work with [NSNumber numberWithInteger:1]? Because iOS tries to be smart. A integer 1 NSNumber is a singleton object which never gets deallocated. [NSNumber numberWithFloat:1.0] is not such an indestructible object, it will get deallocated once its reference count drops to zero. This happens after you leave the scope where the NSNumber instance was created, because it is never retained in your code.

You can see the singleton behaviour with this little logging code, which logs the pointer address of NSNumber instances:

NSLog(@"Address of `[NSNumber numberWithFloat:1.0]`: %p", [NSNumber numberWithFloat:1.0]);
NSLog(@"Address of `[NSNumber numberWithInteger:1]`: %p", [NSNumber numberWithInteger:1]);

NSLog(@"Address of `[NSNumber numberWithFloat:1.0]`: %p", [NSNumber numberWithFloat:1.0]);
NSLog(@"Address of `[NSNumber numberWithInteger:1]`: %p", [NSNumber numberWithInteger:1]);

which yields

Address of `[NSNumber numberWithFloat:1.0]`: 0x10c622d10
Address of `[NSNumber numberWithInteger:1]`: 0xb000000000000013
Address of `[NSNumber numberWithFloat:1.0]`: 0x10c129fb0
Address of `[NSNumber numberWithInteger:1]`: 0xb000000000000013

As you can see the two addresses from numberWithFloat:1.0 differ, and the two addresses from numberWithInteger:1 are the same. Because [NSNumber numberWithInteger:1] always returns the same object.

Upvotes: 5

Related Questions