Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subclassing NSNumber

Tags:

objective-c

I want to add a property to an NSNumber class, so I have to subclass it. The documentation states that I then have to override all NSValue primitive methods. Since the NSValue documentation does not state which methods are the primitive ones, I figured that these two are probably the primitive ones for instantiation:

– initWithBytes:objCType:  
+ valueWithBytes:objCType:

So I made my class as:

@interface MultipleNumber : NSNumber {  
    NSNumber *_number;  
}  
@property (nonatomic, getter = isMultiple) BOOL multiple;  
@end

@implementation MultipleNumber  
@synthesize multiple=_multiple;  

-(id)initWithBytes:(const void *)value objCType:(const char *)type {  
    self = [super init];  
    if (self) {
        _number=[[NSNumber alloc] initWithBytes:value objCType:type];
    }
    return self;
}

+(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type {
   return [[[MultipleNumber alloc] initWithBytes:value objCType:type] autorelease];
}

-(void)getValue:(void *)value { [_number getValue:value]; }

-(const char *)objCType { return [_number objCType]; }

@end

But when I call[NSNumber numberWithBool:YES], I still get a _NSCFBoolean class back and the "primitive methods" are not called. How can I figure out what methods are considered primitive?

like image 716
Remco Poelstra Avatar asked Dec 05 '22 16:12

Remco Poelstra


1 Answers

You don't need to subclass NSNumber in order to add a property. You can add a property more easily using an associative reference. Subclassing NSNumber is quite tricky because it's a class cluster.


EDIT: @Remco makes an important point down in his comments to @diablosnuevos that I wanted to call out in an answer:

Yes, I finally did make a subclass by trial and error, because the NSNumbers returned are shared instances, so storing a associated reference is also shared. – Remco Poelstra May 16 at 9:09

This is a really important thing to remember. NSNumber caches the integers from -1 to 12 and treats them as singletons. In OSX 10.7, NSNumber is implemented as a tagged pointer (haven't dug into the implications for associated references there). The point is that while associated references are quite useful, there can be underlying implementation details that will burn you.

The deeper lesson here is that subclassing or augmenting NSNumber probably isn't a good idea in any case. NSNumber is a very low-level object. It's almost certainly better to build another class that owns an NSNumber, much like NSAttributedString owns an NSString rather than extending NSString.

I don't know the specifics of the problem being solved here, but the problems encountered make for an interesting lesson.

like image 56
Rob Napier Avatar answered Jan 03 '23 04:01

Rob Napier