Why is NSNumber immutable?
Asked Answered
M

7

24

Why is NSNumber immutable? Was there a good reason? Because now I am thinking about creating my own class just for the sake of mutability.

Madson answered 28/4, 2011 at 13:28 Comment(5)
I'm not sure what your question really is. Go ahead and subclass NSNumber (beats moaning here).Seafowl
Not sure why this gets so many down votes. I think immutable is the correct implementation, yet the question is valid (and I think many people asked the same question)Ananthous
I too think this is a perfectly valid question, especially for a beginner maybe coming from another language. If you can't ask on SO where should you ask?Baluchi
I hope the four people who upvoted my comment weren't the four downvoters. I never said the question was bad.Phenomenal
There could well be a valid reason for this. For example you might have an array of booleans that you want to be able to toggle on and off. If the NSArray stores a bunch of [NSNumber numberWithBool:] values should you replace the elements (thus use an NSMutableArray) or can you replace the actual NSNumber instances instead? Point is there may be very valid reasons for having mutability for these.Palatial
A
10

A number is a very basic data type. A number is just that - a number. If you mutate it, it just happens to be something else. A number simply cannot change.

Compare that with more complex data, where the object itself still represents the same thing.

Ananthous answered 28/4, 2011 at 13:49 Comment(6)
Yes but IMHO an NSNumber object is something really fat compared to simply storing an int. I was taught that alloc is a performance killer. And objects are structures with some more fields. Also, an NSNumber seems to store even more information. It's definitely something fat. More fat than just an int. So I was curious why the heck I can't change the instance variable of that object which represents the value. It's after all just an instance variable in an object. It must be like that.Madson
If allocation is local, that is, it is known not to leak to some outside structures in this call and its nested calls, it can just be made on the stack at the expense of one register increment. I don't know whether ObjC compiler can track this, though.Upholstery
Just about everything in your app will be more memory intensive then alloc'ing an NSNumber. You're going to get more bang for your buck looking elsewhere for performance improvements. With that in mind, you may be using NSNumber where a simple int, float etc. is more appropriate.Keyek
Using NSNumber brings another advantage: It can be nil. Using int, float etc. will make you use some kind of hack like constants to represent a missing value.Ananthous
@Ananthous I like your thought that it can be nil and wish say ints had that option too. But I think your comment is in contradiction to the answer that NSNumber is a very basic data type that simply cannot change. The number 5 can never be nil. I am having trouble getting my head round both these concepts at the same time.Caerleon
@Caerleon Actually it's the pointer to the NSNumber that's nil, not the number itself. It's frequently useful for optional attributes. Using some default value is not always appropriate, and later you couldn't tell if it was set manually or not.Ananthous
U
10

Immutable numbers save space. Assume that your program creates many NSNumbers, and most of them happen to be small numbers like 0 or 1. With immutable numbers, you only need a handful objects, one for each distinct value. With mutable numbers, you have as many objects as you have numbers.

Immutable numbers are easy to share. Assume that you wrap a primitive number (like int) with an NSNumber. With immutable NSNumber, the compiler is always sure that the values match, so it can unwrap it and pass the primitive value to function that expect a primitive value. With mutable NSNumber, you can't be sure than another thread did not change the value, and have to actually unwrap it every time, or even think about synchronization. This becomes more costly if the value is passed further and further in nested calls.

Immutable objects have many other useful properties: they are good hash keys, their lifetime and scope is easier to determine, etc. Many functional languages, e.g. Erlang or XSLT, only have immutable data structures.

Upholstery answered 28/4, 2011 at 14:18 Comment(7)
I don't think so. NSNumber is a class like every other, and there are instance methods to return the primitive values. So you mean I can do if(fatNSNumberObj == 33) {...}? Can't believe that.Madson
Probably you're right because what you write sounds clever. But I don't get it. NSNumber is a class, it must have an instance variable to store the value. So when it has that instance variable, it just does not make sense that it is impossible to change it. Or: It is done on purpose. But I don't see where the compiler does unwrap or wrap anything automatically for me. This would mean that the compiler is aware of NSNumber and that I can forget about calling intValue etc. which is just not the case from my experience.Madson
NSNumber has an interface like any other class. But I'm pretty sure that the compiler knows a lot about it and uses various speedups when it's safe. I'm no expert in ObjC, though; let someone more knowledgeable comment on this.Upholstery
I did a test on this. NSNumber is about 50 times slower than simply creating int variables which hold a value. So it's definitely something very heavy compared to a simple int.Madson
I doubt that those two arguments are the reason for NSNumber to be immutable. I don't see how this would speed up things or how they are easier to share, although the latter is close: immutable values are better suitable for threaded code.Manteau
@Upholstery “I'm pretty sure that the compiler knows a lot about it and uses various speedups” see below for a few details on this.Supposing
In 64-bit, some NSNumber objects are really tagged pointers. If the value is small enough, it gets encoded directly inside the pointer and there is no corresponding object allocated in memory. This won't be possible if NSNumber is mutable.Grantgranta
S
7

Eiko makes a good point: a NSNumber represents a basic data type and it makes no sense to make it mutable.

It's like having a int i=0; and asking why 0 is not mutable. And in OS X Lion x64, it is exactly that for integers, because NSNumbers are implemented as tagged pointers, which are pointers that contain data instead an address.

Example, let’s say we want to store the integer 42 in a pointer. We could create a NSNumber and then point to it, or we could replace the address with a 42, in which case we can skip object creation. But how can we tell if we are dealing with a common pointer or a tagged pointer?

A x86 64 pointer has 64 bits, but only uses 48 bits for the pointer address. The reason is that 48 bit provides a 256 TB address space, which is a lot. Using 64 bits would be wasteful because it would require more transistors in the CPU. So the potential address space is 64bit, but current CPUs are only able to use 48. Because of this, the ending bits of a pointer are 0 because they are left unused. We use these last bits to indicate that the pointer is a tagged pointer that represents an integer with a given number of bits.

Therefore, a OS X NSNumber representing an integer is literally just an integer number, but the runtime is able to detect it as a tagged pointer and present it to the user as a common instance.

For other numeric types the implementation is way more complicated, as seen in the NSNumber toll-free Core Foundation counterpart CFNumber.

Supposing answered 13/4, 2013 at 2:0 Comment(0)
P
1

I think everybody had a pretty good answer except maybe 9000. not sure what he's talking about, though maybe it's just over my head.

The decision to make NSNumber immutable is a design decision by the creators of the Foundation Framework. I think we can all agree on that.

I assume the reason they did that was because all of the instantiated objects in Objective-C are referenced using pointers, including NSNumber. This causes some design concerns when passing NSNumber around. Let's say you create a class called "Person", with an NSNumber property, "myAge". So your application instantiates an instance of Person and sets myAge to 28. Some other part of the application now asks the Person object for its age, and it returns (NSNumber*)myAge, or a pointer to the NSNumber object that wraps the value 28. Since a pointer was passed, your Person object now has to wonder if that other part of the application changed the value of myAge!

So NSNumber is immutable, because it is an object meant to hold a value that is free to be created, retrieved, and passed around your application as a value, not as unique object.

Partee answered 22/9, 2011 at 8:6 Comment(0)
P
1

A NSNumber Subclassing example

Note: as documentation says, objCType and value accessor of implemented type (intValue here) must be implemented.

This is done here with a designated initializer (-)init... but this may be done with the (+)method.

@interface NSMutableNumber : NSNumber
{
    int intValue;
}
@property const char *objCType;
+ (id) mutablenumberWithInt:(int)value;
@end

@implementation NSMutableNumber
@synthesize objCType;
+ (id) mutablenumberWithInt:(int)value {
    return [[self alloc] initWithInt:value];
}
- (id) initWithInt:(int)value {
    if (self=[super init]) {
        intValue=value;
        objCType="i";
    }
    return self;
}
- (int)intValue {
    return intValue;
}
- (void)setInt:(int)value {
    intValue=value;
}

@end

Then

    NSMutableNumber *mutn=[NSMutableNumber mutablenumberWithInt:2];
    NSLog(@"%@\n", mutn);

    // return 2

    [mutn setInt:4];
    NSLog(@"%@\n", mutn);

    // return 4
Perfective answered 12/5, 2014 at 7:49 Comment(0)
M
0

I guess it is immutable, like other classes (NSArray, NSString, etc.), because immutable objects are easier to use and share and pass around in threaded code. See wikipedia.

Manteau answered 28/7, 2011 at 14:56 Comment(0)
S
0

If you want to create your on NSMutableNumber for whatever reason, and in order for you class to work properly, you would have to override most of the methods except a few; Keep in mind that changing a value of any type will result in changing all the others, and will update the objCType property, so you would want to override your setters accordingly as well. I have written such a subclass that is mutable and behaves mostly like an NSNumber with a few different details and extra methods; The description for a BOOL type now returns a YES or NO string instead of 1 or 0, also I have added initWithDecimal, numberWithDecimal, initWithLongDouble and numberWithLongDouble methods as well. here it goes:

Here is your NSMutableNumber.h file:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSMutableNumber : NSNumber
@property(nonatomic, readwrite) BOOL boolValue;
@property(nonatomic, readwrite) char charValue;
@property(nonatomic, readwrite) unsigned char unsignedCharValue;
@property(nonatomic, readwrite) short shortValue;
@property(nonatomic, readwrite) unsigned short unsignedShortValue;
@property(nonatomic, readwrite) int intValue;
@property(nonatomic, readwrite) unsigned int unsignedIntValue;
@property(nonatomic, readwrite) NSInteger integerValue;
@property(nonatomic, readwrite) NSUInteger unsignedIntegerValue;
@property(nonatomic, readwrite) long longValue;
@property(nonatomic, readwrite) unsigned long unsignedLongValue;
@property(nonatomic, readwrite) long long longLongValue;
@property(nonatomic, readwrite) unsigned long long unsignedLongLongValue;
@property(nonatomic, readwrite) float floatValue;
@property(nonatomic, readwrite) double doubleValue;
@property(nonatomic, readwrite) long double longDoubleValue;
@property(nonatomic, readwrite) NSDecimal decimalValue;
@property(nonatomic, readwrite) const char *objCType;

+ (NSMutableNumber *)numberWithBool:(BOOL)value;
+ (NSMutableNumber *)numberWithChar:(char)value;
+ (NSMutableNumber *)numberWithUnsignedChar:(unsigned char)value;
+ (NSMutableNumber *)numberWithShort:(short)value;
+ (NSMutableNumber *)numberWithUnsignedShort:(unsigned short)value;
+ (NSMutableNumber *)numberWithInt:(int)value;
+ (NSMutableNumber *)numberWithUnsignedInt:(unsigned int)value;
+ (NSMutableNumber *)numberWithInteger:(NSInteger)value;
+ (NSMutableNumber *)numberWithUnsignedInteger:(NSUInteger)value;
+ (NSMutableNumber *)numberWithLong:(long)value;
+ (NSMutableNumber *)numberWithUnsignedLong:(unsigned long)value;
+ (NSMutableNumber *)numberWithLongLong:(long long)value;
+ (NSMutableNumber *)numberWithUnsignedLongLong:(unsigned long long)value;
+ (NSMutableNumber *)numberWithFloat:(float)value;
+ (NSMutableNumber *)numberWithDouble:(double)value;
+ (NSMutableNumber *)numberWithLongDouble:(long double)value;
+ (NSMutableNumber *)numberWithDecimal:(NSDecimal)value;

- (NSMutableNumber *)initWithBool:(BOOL)value;
- (NSMutableNumber *)initWithChar:(char)value;
- (NSMutableNumber *)initWithUnsignedChar:(unsigned char)value;
- (NSMutableNumber *)initWithShort:(short)value;
- (NSMutableNumber *)initWithUnsignedShort:(unsigned short)value;
- (NSMutableNumber *)initWithInt:(int)value;
- (NSMutableNumber *)initWithUnsignedInt:(unsigned int)value;
- (NSMutableNumber *)initWithInteger:(NSInteger)value;
- (NSMutableNumber *)initWithUnsignedInteger:(NSUInteger)value;
- (NSMutableNumber *)initWithLong:(long)value;
- (NSMutableNumber *)initWithUnsignedLong:(unsigned long)value;
- (NSMutableNumber *)initWithLongLong:(long long)value;
- (NSMutableNumber *)initWithUnsignedLongLong:(unsigned long long)value;
- (NSMutableNumber *)initWithFloat:(float)value;
- (NSMutableNumber *)initWithDouble:(double)value;
- (NSMutableNumber *)initWithLongDouble:(long double)value;
- (NSMutableNumber *)initWithDecimal:(NSDecimal)value;
- (NSString *)stringValue;
- (NSString *)description;
- (NSString *)descriptionWithLocale:(NSLocale *)locale;

@end

NS_ASSUME_NONNULL_END

Here is your NSMutableNumber.m file:

#import "NSMutableNumber.h"

@interface NSMutableNumber ()
- (void)setAllIntValues:(unsigned long long)ULLongVal allFloats:(long double)LDoubleVal;
- (NSMutableNumber *)initAllints:(unsigned long long)ULLongVal allFloats:(long double)LDoubleVal;
@end

@implementation NSMutableNumber
@synthesize boolValue;
@synthesize charValue;
@synthesize unsignedCharValue;
@synthesize shortValue;
@synthesize unsignedShortValue;
@synthesize intValue;
@synthesize unsignedIntValue;
@synthesize integerValue;
@synthesize unsignedIntegerValue;
@synthesize longValue;
@synthesize unsignedLongValue;
@synthesize longLongValue;
@synthesize unsignedLongLongValue;
@synthesize floatValue;
@synthesize doubleValue;
@synthesize decimalValue;
@synthesize objCType;

// Designated initializer - private method
- (NSMutableNumber *)initAllints:(unsigned long long)ULLongVal allFloats:(long double)LDoubleVal
{
    boolValue = ULLongVal;
    charValue = (char)ULLongVal;
    unsignedCharValue = (unsigned char)ULLongVal;
    shortValue = (short)ULLongVal;
    unsignedShortValue = (unsigned short)ULLongVal;
    intValue = (int)ULLongVal;
    unsignedIntValue = (unsigned int)ULLongVal;
    integerValue = (NSInteger)ULLongVal;
    unsignedIntegerValue = (NSUInteger)ULLongVal;
    longValue = ULLongVal;
    unsignedLongValue = ULLongVal;
    longLongValue = ULLongVal;
    unsignedLongLongValue = ULLongVal;
    floatValue = LDoubleVal;
    doubleValue = LDoubleVal;
    _longDoubleValue = LDoubleVal;
    NSNumber *decimalNumber = [NSNumber numberWithUnsignedLongLong:LDoubleVal];
    NSDecimal decimal = [decimalNumber decimalValue];
    decimalValue = decimal;
    return self;
}
// Private method
- (void)setAllIntValues:(unsigned long long)ULLongVal allFloats:(long double)LDoubleVal
{
    boolValue = ULLongVal;
    charValue = (char)ULLongVal;
    unsignedCharValue = (unsigned char)ULLongVal;
    shortValue = (short)ULLongVal;
    unsignedShortValue = (unsigned short)ULLongVal;
    intValue = (int)ULLongVal;
    unsignedIntValue = (unsigned int)ULLongVal;
    integerValue = (NSInteger)ULLongVal;
    unsignedIntegerValue = (NSUInteger)ULLongVal;
    longValue = ULLongVal;
    unsignedLongValue = ULLongVal;
    longLongValue = ULLongVal;
    unsignedLongLongValue = ULLongVal;
    floatValue = LDoubleVal;
    doubleValue = LDoubleVal;
    _longDoubleValue = LDoubleVal;
    NSNumber *decimalNumber = [NSNumber numberWithUnsignedLongLong:LDoubleVal];
    NSDecimal decimal = [decimalNumber decimalValue];
    decimalValue = decimal;
}
+ (NSMutableNumber *)numberWithBool:(BOOL)value
{
    return [[super alloc] initWithBool:value];
}
+ (NSMutableNumber *)numberWithChar:(char)value
{
    return [[super alloc] initWithChar:value];
}
+ (NSMutableNumber *)numberWithUnsignedChar:(unsigned char)value
{
    return [[super alloc] initWithUnsignedChar:value];
}
+ (NSMutableNumber *)numberWithShort:(short)value
{
    return [[super alloc] initWithShort:value];
}
+ (NSMutableNumber *)numberWithUnsignedShort:(unsigned short)value
{
    return [[super alloc] initWithUnsignedShort:value];
}
+ (NSMutableNumber *)numberWithInt:(int)value
{
    return [[super alloc] initWithInt:value];
}
+ (NSMutableNumber *)numberWithUnsignedInt:(unsigned int)value
{
    return [[super alloc] initWithUnsignedInt:value];
}
+ (NSMutableNumber *)numberWithInteger:(NSInteger)value
{
    return [[super alloc] initWithInteger:value];
}
+ (NSMutableNumber *)numberWithUnsignedInteger:(NSUInteger)value
{
    return [[super alloc] initWithUnsignedInteger:value];
}
+ (NSMutableNumber *)numberWithLong:(long)value
{
    return [[super alloc] initWithLong:value];
}
+ (NSMutableNumber *)numberWithUnsignedLong:(unsigned long)value
{
    return [[super alloc] initWithUnsignedLong:value];
}
+ (NSMutableNumber *)numberWithLongLong:(long long)value
{
    return [[super alloc] initWithLongLong:value];
}
+ (NSMutableNumber *)numberWithUnsignedLongLong:(unsigned long long)value
{
    return [[super alloc] initWithUnsignedLongLong:value];
}
+ (NSMutableNumber *)numberWithFloat:(float)value
{
    return [[super alloc] initWithFloat:value];
}
+ (NSMutableNumber *)numberWithDouble:(double)value
{
    return [[super alloc] initWithDouble:value];
}
+ (NSMutableNumber *)numberWithLongDouble:(long double)value
{
    return [[super alloc] initWithLongDouble:value];
}
+ (NSMutableNumber *)numberWithDecimal:(NSDecimal)value
{
    return [[super alloc] initWithDecimal:value];
}
- (NSMutableNumber *)initWithBool:(BOOL)value;
{
    if (self = [super init]) {
        objCType = @encode(BOOL);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithChar:(char)value
{
    if (self = [super init]) {
        objCType = @encode(char);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithUnsignedChar:(unsigned char)value
{
    if (self = [super init]) {
        objCType = @encode(unsigned char);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithShort:(short)value
{
    if (self = [super init]) {
        objCType = @encode(short);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithUnsignedShort:(unsigned short)value
{
    if (self = [super init]) {
        objCType = @encode(unsigned short);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithInt:(int)value
{
    if (self = [super init]) {
        objCType = @encode(int);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithUnsignedInt:(unsigned int)value
{
    if (self = [super init]) {
        objCType = @encode(unsigned int);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithInteger:(NSInteger)value
{
    if (self = [super init]) {
        objCType = @encode(NSInteger);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithUnsignedInteger:(NSUInteger)value
{
    if (self = [super init]) {
        objCType = @encode(NSUInteger);
        self =[self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithLong:(long)value
{
    if (self = [super init]) {
        objCType = @encode(long);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithUnsignedLong:(unsigned long)value
{
    if (self = [super init]) {
        objCType = @encode(unsigned long);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithLongLong:(long long)value
{
    if (self = [super init]) {
        objCType = @encode(long long);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithUnsignedLongLong:(unsigned long long)value
{
    if (self = [super init]) {
        objCType = @encode(unsigned long long);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithFloat:(float)value
{
    if (self = [super init]) {
        objCType = @encode(float);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithDouble:(double)value
{
    if (self = [super init]) {
        objCType = @encode(double);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithLongDouble:(long double)value
{
    if (self = [super init]) {
        objCType = @encode(long double);
        self = [self initAllints:value allFloats:value];
    }
    return self;
}
- (NSMutableNumber *)initWithDecimal:(NSDecimal)value
{
    if (self = [super init]) {
        objCType = @encode(NSDecimal);
        decimalValue = value;
        NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithDecimal:value];
        unsigned long long UlongLongVal = [decimalNumber unsignedLongLongValue];
        long double LDoubleVal = [decimalNumber doubleValue];
        boolValue = UlongLongVal;
        charValue = (char)UlongLongVal;
        unsignedCharValue = (unsigned char)UlongLongVal;
        shortValue = (short)UlongLongVal;
        unsignedShortValue = (unsigned short)UlongLongVal;
        intValue = (int)UlongLongVal;
        unsignedIntValue = (unsigned int)UlongLongVal;
        integerValue = (NSInteger)UlongLongVal;
        unsignedIntegerValue = (NSUInteger)UlongLongVal;
        longValue = (long)UlongLongVal;
        unsignedLongValue = (unsigned long)UlongLongVal;
        longLongValue = (long long)UlongLongVal;
        unsignedLongLongValue = (unsigned long long)UlongLongVal;
        floatValue = (float)LDoubleVal;
        doubleValue = (double)LDoubleVal;
        _longDoubleValue = LDoubleVal;
    }
    return self;
}
- (NSString *)stringValue
{
    NSLocale *locale = [NSLocale systemLocale];
    return [self descriptionWithLocale:locale];
}
- (NSString *)description
{
    return [self stringValue];
}
- (NSString *)descriptionWithLocale:(NSLocale *)locale
{
    NSString *description;
    NSString *(^desc)(NSLocale *locale, NSString *format, ...);
    desc = ^(NSLocale *locale, NSString *format, ...) {
        va_list args;
        va_start (args, format);
        NSString *valueAsString = [[NSString alloc] initWithFormat:format locale:locale arguments:args];
        va_end(args);
        return valueAsString;
    };
    if (strcmp(objCType, @encode(BOOL)) == 0) {
        if (self.boolValue) {
            description = desc(locale, @"%YES");
        } else {
            description = desc(locale, @"%NO");
        }
    } else if (strcmp(objCType, @encode(char)) == 0) {
        description = desc(locale, @"%hhi", self.charValue);
    } else if (strcmp(objCType, @encode(unsigned char)) == 0) {
        description = desc(locale, @"%hhu", self.unsignedCharValue);
    } else if (strcmp(objCType, @encode(short)) == 0) {
        description = desc(locale, @"%hd", self.shortValue);
    } else if (strcmp(objCType, @encode(unsigned short)) == 0) {
        description = desc(locale, @"%hu", self.unsignedShortValue);
    } else if (strcmp(objCType, @encode(int)) == 0) {
        description = desc(locale, @"%d", self.intValue);
    } else if (strcmp(objCType, @encode(unsigned int)) == 0) {
        description = desc(locale, @"%u", self.unsignedIntValue);
    } else if (strcmp(objCType, @encode(NSInteger)) == 0) {
        description = desc(locale, @"%ld", (long)self.integerValue);
    } else if (strcmp(objCType, @encode(NSUInteger)) == 0) {
        description = desc(locale, @"%lu", (long)self.unsignedIntegerValue);
    } else if (strcmp(objCType, @encode(long)) == 0) {
        description = desc(locale, @"%ld", self.longValue);
    } else if (strcmp(objCType, @encode(unsigned long)) == 0) {
        description = desc(locale, @"%lu", self.unsignedLongValue);
    } else if (strcmp(objCType, @encode(long long)) == 0) {
        description = desc(locale, @"%lld", self.longLongValue);
    } else if (strcmp(objCType, @encode(unsigned long long)) == 0) {
        description = desc(locale, @"%llu", self.unsignedLongLongValue);
    } else if (strcmp(objCType, @encode(float)) == 0) {
        description = desc(locale, @"%f", self.floatValue);
    } else if (strcmp(objCType, @encode(double)) == 0) {
        description = desc(locale, @"%lf", self.doubleValue);
    } else if (strcmp(objCType, @encode(long double)) == 0) {
        description = desc(locale, @"%Lf", self.longDoubleValue);
    } else if (strcmp(objCType, @encode(NSDecimal)) == 0) {
        NSDecimalNumber *decimal = [NSDecimalNumber decimalNumberWithDecimal:decimalValue];
        description = desc(locale, @"%@", [decimal stringValue]);
    }
    return description;
}
- (void)setBoolValue:(BOOL)value
{
    objCType = @encode(BOOL);
    [self setAllIntValues:value allFloats:value];
}

- (void)setCharValue:(char)value
{
    objCType = @encode(char);
    [self setAllIntValues:value allFloats:value];
}

- (void)setUnsignedCharValue:(unsigned char)value
{
    objCType = @encode(unsigned char);
    [self setAllIntValues:value allFloats:value];
}
- (void)setShortValue:(short)value
{
    objCType = @encode(short);
    [self setAllIntValues:value allFloats:value];
}
- (void)setUnsignedShortValue:(unsigned short)value
{
    objCType = (@encode(unsigned short));
    [self setAllIntValues:value allFloats:value];
}
-(void)setIntValue:(int)value
{
    objCType = @encode(int);
    [self setAllIntValues:value allFloats:value];
}
-(void)setUnsignedIntValue:(unsigned int)value
{
    objCType = @encode(unsigned int);
    [self setAllIntValues:value allFloats:value];
}
- (void)setIntegerValue:(NSInteger)value
{
    objCType = @encode(NSInteger);
    [self setAllIntValues:value allFloats:value];
}
- (void)setUnsignedIntegerValue:(NSUInteger)value
{
    objCType = @encode(NSUInteger);
    [self setAllIntValues:value allFloats:value];
}
- (void)setLongValue:(long)value
{
    objCType = @encode(long);
    [self setAllIntValues:value allFloats:value];
}
- (void)setUnsignedLongValue:(unsigned long)value
{
    objCType = @encode(unsigned long);
    [self setAllIntValues:value allFloats:value];
}
- (void)setLongLongValue:(long long)value
{
    objCType = @encode(long long);
    [self setAllIntValues:value allFloats:value];
}
- (void)setUnsignedLongLongValue:(unsigned long long)value
{
    objCType = @encode(unsigned long long);
    [self setAllIntValues:value allFloats:value];
}
- (void)setFloatValue:(float)value
{
    objCType = @encode(float);
    [self setAllIntValues:value allFloats:value];
}
- (void)setDoubleValue:(double)value
{
    objCType = @encode(double);
    [self setAllIntValues:value allFloats:value];
}
- (void)setLongDoubleValue:(long double)value
{
    objCType = @encode(long double);
    [self setAllIntValues:value allFloats:value];
}
- (void)setDecimalValue:(NSDecimal)value
{
    objCType = @encode(NSDecimal);
    decimalValue = value;
    NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithDecimal:value];
    unsigned long long UlongLongVal = [decimalNumber unsignedLongLongValue];
    long double LDoubleVal = [decimalNumber doubleValue];
    boolValue = UlongLongVal;
    charValue = (char)UlongLongVal;
    unsignedCharValue = (unsigned char)UlongLongVal;
    shortValue = (short)UlongLongVal;
    unsignedShortValue = (unsigned short)UlongLongVal;
    intValue = (int)UlongLongVal;
    unsignedIntValue = (unsigned int)UlongLongVal;
    integerValue = (NSInteger)UlongLongVal;
    unsignedIntegerValue = (NSUInteger)UlongLongVal;
    longValue = (long)UlongLongVal;
    unsignedLongValue = (unsigned long)UlongLongVal;
    longLongValue = (long long)UlongLongVal;
    unsignedLongLongValue = (unsigned long long)UlongLongVal;
    floatValue = (float)LDoubleVal;
    doubleValue = (double)LDoubleVal;
    _longDoubleValue = LDoubleVal;}
@end
Swann answered 21/12, 2022 at 12:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.