问题
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.
回答1:
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.
回答2:
Immutable numbers save space. Assume that your program creates many NSNumber
s, 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.
回答3:
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.
回答4:
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.
回答5:
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.
回答6:
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
来源:https://stackoverflow.com/questions/5819387/why-is-nsnumber-immutable