Ios 为什么NSDictionary实现为类集群?

Ios 为什么NSDictionary实现为类集群?,ios,objective-c,macos,cocoa,foundation,Ios,Objective C,Macos,Cocoa,Foundation,类集群将许多私有的具体子类分组到公共抽象超类下。以NSNumber为例;以下每个便利构造函数返回一个不同的私有子类NSNumber: NSNumber *aChar = [NSNumber numberWithChar:’a’]; NSNumber *anInt = [NSNumber numberWithInt:1]; NSNumber *aFloat = [NSNumber numberWithFloat:1.0]; NSNumber *aDouble = [NSNumber numberW

类集群将许多私有的具体子类分组到公共抽象超类下。以
NSNumber
为例;以下每个便利构造函数返回一个不同的私有子类
NSNumber

NSNumber *aChar = [NSNumber numberWithChar:’a’];
NSNumber *anInt = [NSNumber numberWithInt:1];
NSNumber *aFloat = [NSNumber numberWithFloat:1.0];
NSNumber *aDouble = [NSNumber numberWithDouble:1.0];
文档中解释了在此处使用类集群的动机:

因为不同类型的数字有许多共同的特性(例如,它们可以从一种类型转换为另一种类型,并可以表示为字符串),所以它们可以由单个类表示。但是,它们的存储需求不同,因此用同一个类来表示它们是低效的

类簇的其他示例包括
NSString
NSData
NSArray
NSDictionary
。基于上述解释,我理解了为什么可以将
NSString
NSData
实现为类集群。毕竟,
NSString
实例的存储需求可能会因其是使用C字符串还是
CFString
初始化而有所不同

但是为什么
NSArray
NSDictionary
?似乎应该将这两个类都实现为
CFMutableArray
CFMutableDictionary
的包装器。毕竟,
NSDictionary
可以将任何东西存储为键或值;不知道存储需求是什么。因此,存储CFDictionary似乎是一条出路

例如,
NSDictionary
可以实现为以下
NSXDictionary

// NSXDictionary.m

@interface NSXDictionary ()
@property (nonatomic, assign) CFMutableDictionaryRef dictionary;
@end

@implementation NSXDictionary

- (instancetype)init {
    self = [super init];
    if (self) {
        _dictionary = CFDictionaryCreateMutable(NULL,
                                                0,
                                                &kCFTypeDictionaryKeyCallBacks,
                                                &kCFTypeDictionaryValueCallBacks);
    }
    return self;
}

- (void)dealloc {
    CFRelease(_dictionary);
}

- (NSUInteger)count {
    return CFDictionaryGetCount(self.dictionary);
}

- (id)objectForKey:(id)aKey {
    return CFDictionaryGetValue(self.dictionary, (__bridge const void *)(aKey));
}

@end

我的问题是:
NSDictionary
为什么实现为类集群?将其实现为一个具体的类,并将其子类化是不是会更简单?

构建NSDictionary有多少种不同的方法

有几种方法(initWithContentsOfFile、initWithObjectsAndKeys等)更容易通过创建内部可变大小的对象、填充它,然后将其标记为不可变来实现

其他(initWithObjects:forKeys:count:、initWithDictionary、init、
@{}
)可以由固定大小(但仍然是暂时可变的)对象很好地服务

然后你有可变/不可变的变化

不是简单的类层次结构。从性能、占用的空间和创建的对象数量的角度来看,包装类不如类层次结构


(当然,还有一个最重要的答案:因为苹果公司发号施令,这就是他们的决定。)

它被实现为一个类集群,因为它可以返回
NSDictionary
NSMutableDictionary

NSMutableDictionary *mutableDict = [dict mutableCopy];

NSDictionary *dict = [mutableDict copy];
比如:

苹果公司文档中也指出:

在此链接:


与NSDictionary和NSMutableDictionary相比,您的类的性能如何?这一决定背后可能有性能方面的原因。NSMutableDictionary是为了CFMutableDictionaryRef,因此您根本不需要包装器。任何NSMutableDictionary都可以用作CFMutableDictionaryRef,反之亦然。更好的问题是
为什么要关心?
NSDictionary可以向您提供NSCFDictionary、NSDictionary[I/M]或某些代理,或运行时视为字典的标记指针。没关系,只要它像字典一样走路和说话。将集合实现为类集群可以保证长期的API完整性,因此当出现更好的情况时,它们只需交换它们提供给您的内容,您甚至不会注意到任何事情。我相信我理解您的观点,@CodaFi,但在具体类上维护公共接口也可以保证长期的API完整性。苹果仍然可以自由地更换该实现。至于我为什么在意:一位同事问我如何实现
NSDictionary
。我开始解释类集群,但后来意识到我不知道为什么
NSDictionary
首先使用类集群实现。我明白,作为苹果API的消费者,我不应该依赖内部实现细节。但是,对于我来说,关于如何实现某件事情以及为什么以这种方式实现它的推理似乎是一项有价值的脑力练习。这就是我关心的原因。这很有道理,谢谢!我可能会接受这个答案,但你能详细说明一下“从占用空间和创建对象数量的角度来看,包装类不如类层次结构好吗?”?也就是说,类层次结构如何创建更少的对象?@modocache-包装类是与其包装的对象分开的对象。子类只是扩展了它的超类的定义——只有一个对象。你读错了表:NSData是为公共超类服务的类集群。但是你的回答没有包含任何关于类集群实现的内容。对不起,伙计,但是你还没有理解什么是类集群。但是嘿:也许向版主抱怨会有帮助!这是错误的。它不抱怨任何事情,其他类也有mutableCopy/copy消息。您不涉及任何对理解集群至关重要的私有类集群类。我会投票否决不好和不正确的答案。您的答案同时满足了这两个条件,但您错了:没有返回NSMutableDictionary,而是返回了一个uu NSDictionaryM。没有一本字典被退回,但可能是NSCFDictionary或a_uunsyi。这是一个类集群:返回私有的和可变的子类对象。你所描述的只是方便的方法。
NSString/NSMutableString 
NSData/NSMutableData
NSArray/NSMutableArray