在Objective C中有一个类似NSArray,NSDictionary等类的可变和不可变版本的逻辑是什么?

NSE*_*rer 20 iphone class-design objective-c foundation ios

为什么Objective C中的常见集合类(如NSString,NSArray,NSDictionary等)具有可变版本和不可变版本.分别定义它们的逻辑是什么?性能,内存管理还是其他什么?

bbu*_*bum 14

存在类的不可变版本,因为不可变对象本身就是特定状态唯一标识符.即如果你有NSArray100个NSString实例,那么该NSArray实例可以被视为对这些字符串中的任何一个都是幂等的.

同样,不变性意味着在国家出售后不会发生变化.例如,NSView's subviews方法返回一个不可变数组,从而确保调用者不会使用内容玩游戏(甚至不能期望).在内部,NSView 可以选择退货的[可能] NSMutableArray中包含的子视图(因为它是内部可变)和强制转换NSArray是指没有一个邪恶的施法或坏的编译器警告调用者不能处理的内容.(这可能是也可能不是真正的实现,顺便说一句 - 但这种模式在其他地方使用).

不可变性还意味着可以在没有中间状态变化风险的情况下进行枚举和/或遍历.类似地,许多不可变类也明确地是线程安全的; 任意数量的线程都可以同时读取不可变状态,通常不需要锁定.


Ken*_*ner 12

通常对于API,不可变类将是线程安全的,因此您可以直接在后台线程中读取它而不必担心内容会发生变化......

对于像内容可以移动的集合这样的东西更重要,你可能正在枚举它们.

  • 实际上,记录了不可变NS集合和不可变NSStrings的线程安全性(但是,是的,不变性,通常并不意味着线程安全).由于内部实现细节(例如缓存填充),有大量不可变对象的示例不是线程安全的. (2认同)

jus*_*tin 10

为什么Objective C中的常见集合类(如NSString,NSArray,NSDictionary等)具有可变版本和不可变版本.

该概念用于相关语言.值得注意的区别是objc类型被命名为可变变体.类似的语言通常通过应用关键字来实现这一点,例如const.当然,其他相关语言也使用明确可变或不可变的类型.

分别定义它们的逻辑是什么?

objc消息传递不区分const和非const,并且该语言不提供内置支持来确保对象的状态不会改变(尽管如果真的倾向于扩展编译器,它确实不会是一个困难的补充).所以这里也有一点历史.

因此,该类的惯例是定义不变性和可变性,并提供区分可变性的变体.

多个抽象也引入了类型安全和意图.

性能

是.不变对象可以进行多种优化.

一些案例包括:

  • 它可以缓存值,永远不会多次计算它们.
  • 它可以对其数据使用精确的,不可调整的分配.
  • 它通常不需要任何特殊的代码用于多线程使用 - 许多不可变类型只会在构造/销毁期间发生变异.
  • 这些类型通常使用类集群.如果实现了类集群,那么专门的实现可以在内存,实现等方面提供显着的差异.考虑具有恰好一个字符的不可变字符串如何可能与可变变体不同.

内存管理

一些案例包括:

  • 不可变类型可以共享其不可变内容.
  • 他们也可能减少分配.例如,保留源的实现copyWithZone:或者initWithType:可以返回源,而不是深层或浅层的物理副本.

或其他什么?

它使编写清晰的接口变得更容易.你可以保证和(试图)限制某些事情.如果一切都是可变的,那么会有更多的错误和特殊情况.事实上,这种区别可能会完全改变我们编写objc库的方式:

[[textField stringValue] appendString:@" Hz"];
[textField stateDidChange];
Run Code Online (Sandbox Code Playgroud)

所以很高兴能够传递物体而不必担心客户会在你背后改变,同时避免在整个地方进行复制.


Dav*_*ong 8

基本上,当您知道数据结构是不可变的时,您可以围绕它进行许多优化.例如,如果一个数组是不可变的,那么只要你试图添加一个对象就可以省去所有会"增长"数组的代码,你可以简单地让你的不可变数组成为一个包装器id[].