For various reasons, I need to associate a default number format (a NSNumberFormatter
) with NSNumber
objects. I want to support this even for objects created outside my control, hence rather than create a sub-class of NSNumber, I have used a category and the ObjC associated object functionality to achieve this:
@interface NSNumber (defaultNumberFormat)
@property (nonatomic,strong) NSNumberFormatter *defaultNumberFormat;
@end
@implementation NSNumber (defaultNumberFormat)
@dynamic defaultNumberFormat;
- (void)setDefaultNumberFormat:(NSNumberFormatter *)format {
[self willChangeValueForKey:@"defaultNumberFormat"];
objc_setAssociatedObject(self, @selector(defaultNumberFormat), format, OBJC_ASSOCIATION_COPY_NONATOMIC);
[self didChangeValueForKey:@"defaultNumberFormat"];
}
- (NSNumberFormatter *)defaultNumberFormat {
return objc_getAssociatedObject(self, @selector(defaultNumberFormat));
}
@end
This works well under a 32 bit compile, however under iOS7 for 64 bit targets, for some values it crashes with EXC_BAD_ACCESS (code=EXC_I386_GPFLT) at the obj_setAssociatedObject
call.
It turns out that the reason is iOS is using tagged pointers for 64 bit targets for selected objects with small values to improve performance (avoids the need for memory allocation and ARC cleanup for the object). This includes some NSString, NSNumber and NSDate values. See more information here and here.
So how do you achieve a category with a property for NSNumber under 64 bit mode?