为什么NSNumber不可变?有充分的理由吗?因为现在我正在考虑为了可变性而创建我自己的类。
答案 0 :(得分:10)
数字是非常基本数据类型。一个数字就是 - 一个数字。如果你改变它,它恰好是其他东西。一个数字根本无法改变。
将它与更复杂的数据进行比较,其中对象本身仍代表相同的东西。
答案 1 :(得分:10)
不可变数字可以节省空间。假设你的程序创建了许多NSNumber
,并且大多数都是0或1之类的小数字。使用不可变数字,你只需要一个少数对象,每个不同的值。使用可变数字,您拥有与数字一样多的对象。
不可分割的数字很容易分享。假设您使用int
包装原始数字(如NSNumber
)。对于不可变NSNumber
,编译器始终确保值匹配,因此它可以解包并将原始值传递给期望原始值的函数。对于可变NSNumber
,您无法确定是否有另一个线程没有更改该值,并且每次都必须实际解开它,甚至考虑同步。如果在嵌套调用中进一步传递该值,则会变得更加昂贵。
不可变对象具有许多其他有用的属性:它们是良好的散列键,它们的生命周期和范围更容易确定等。许多函数语言,例如Erlang或XSLT, only 具有不可变数据结构。
答案 2 :(得分:6)
Eiko提出了一个很好的观点:NSNumber代表了一种基本的数据类型,让它变得可变是没有意义的。
就像拥有int i=0;
并询问为什么0不可变。在OS X Lion x64中,它正好是整数,因为NSNumbers实现为tagged pointers,它们是包含数据而不是地址的指针。
示例,假设我们要将整数42存储在指针中。我们可以创建一个NSNumber然后指向它,或者我们可以用42替换地址,在这种情况下我们可以跳过对象创建。但是我们如何判断我们是在处理公共指针还是标记指针?
x86 64指针有64位,但指针地址只使用48位。原因是48位提供了256 TB的地址空间,这是很多。使用64位将是浪费,因为它需要CPU中更多的晶体管。因此潜在的地址空间是64位,但是当前的CPU只能使用48.因此,指针的结束位为0,因为它们未被使用。我们使用这些最后一位来指示指针是一个标记指针,表示具有给定位数的整数。
因此,表示整数的OS X NSNumber实际上只是一个整数,但运行时能够将其检测为标记指针并将其作为公共实例呈现给用户。
对于其他数字类型,实现方式更复杂,如NSNumber免费核心基金会对应CFNumber中所示。
答案 3 :(得分:1)
我认为除了9000之外,每个人都有一个非常好的答案。不确定他在说什么,虽然也许只是在我头上。
使NSNumber不可变的决定是Foundation Framework创建者的设计决策。我想大家都同意这一点。
我认为他们这样做的原因是因为Objective-C中的所有实例化对象都是使用指针引用的,包括NSNumber。这会在传递NSNumber时引起一些设计问题。假设您创建了一个名为“Person”的类,其中包含NSNumber属性“myAge”。因此,您的应用程序实例化Person的实例并将myAge设置为28.应用程序的其他部分现在向Person对象询问其年龄,并返回(NSNumber *)myAge或指向包装值28的NSNumber对象的指针。由于传递了一个指针,你的Person对象现在不得不想知道应用程序的其他部分是否改变了myAge的值!
因此,NSNumber是不可变的,因为它是一个对象,意味着保存一个值,该值可以作为值自由创建,检索和传递给应用程序,而不是唯一对象。
答案 4 :(得分:0)
我认为它是不可变的,就像其他类(NSArray,NSString等)一样,因为不可变对象更容易使用并在线程代码中共享和传递。请参阅wikipedia。
答案 5 :(得分:0)
NSNumber子类化示例
注意:正如文档所述,必须实现objCType和已实现类型的值访问器(此处为intValue)。
这是通过指定的初始值设定项( - )init来完成的,但这可以使用(+)方法完成。
@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
然后
NSMutableNumber *mutn=[NSMutableNumber mutablenumberWithInt:2];
NSLog(@"%@\n", mutn);
// return 2
[mutn setInt:4];
NSLog(@"%@\n", mutn);
// return 4