为什么NSNumber不可变?

时间:2011-04-28 13:28:58

标签: objective-c nsnumber

为什么NSNumber不可变?有充分的理由吗?因为现在我正在考虑为了可变性而创建我自己的类。

6 个答案:

答案 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