I am trying to create Price class that extends NSDecimalNumber but when trying to alloc it and init it is raising exceptions. Any idea what can be a problem?
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Did you forget to nest alloc and initWithString: ?'
Price.h
#import <Foundation/Foundation.h>
@interface Price : NSDecimalNumber
+ (Price*)priceWithString:(NSString*)val;
@end
Price.m
#import "Price.h"
@implementation Price
- (NSString *)description {
return [[super description] stringByAppendingString:@" €"];
}
+ (Price*)priceWithString:(NSString*)val {
return [[Price alloc] initWithString:val];
}
@end
Edit: Even bare class is not working. If I am extending NSDecimalNumber and then trying to do alloc init, the same exception. I gave up at this...
NSDecimalNumber
inherits NSNumber
, which is a class cluster. This makes it very tough to inherit NSDecimalNumber
, because there is a number of additional requirements for such inheriting. According to Apple documentation, your class needs to
- Be a subclass of the cluster’s abstract superclass
- Declare its own storage
- Override all initializer methods of the superclass
- Override the superclass’s primitive methods (described below)
In your case, your Price
class would need to re-implement a lot of NSDecimalNumber
, which is probably too much work.
A better approach would be to nest NSDecimalNumber
inside your Price
class, and add a method to obtain its numeric value, like this:
@interface Price : NSObject
/// Represents the numeric value of the price
@property (nonatomic, readonly) NSDecimalNumber *valueInLocalCurrency;
/// Represents the pricing currency
@property (nonatomic, readonly) NSString *currencyCode;
/// Creates an immutable Price object
-(id)initWithPriceInLocalCurrency:(NSDecimalNumber*)price andCurrencyCode:(NSString*)currencyCode;
@end
Once consequence of this decision is that you can no longer send a Price
object to places where an NSDecimalNumber
object is expected. This has a potential of preventing silly errors when you disregard the currency by mistake, so it is probably a good safety measure.