Objective C 中 NSArray、NSDictionary 等类的可变和不可变版本背后的逻辑是什么?
为什么 Objective C 中常见的集合类(如 NSString、NSArray、NSDictionary 等)有可变版本和不可变版本。分别定义它们背后的逻辑是什么?性能、内存管理还是其他什么?
Why do common collection classes in Objective C like NSString, NSArray, NSDictionary etc have a mutable as well as an immutable version. What is the logic behind defining them separately? Performance, memory management or anything else?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
类的不可变版本之所以存在,是因为不可变对象本身就是特定状态的唯一标识符。也就是说,如果您有一个包含 100 个
NSString
实例的NSArray
,则该NSArray
实例对于这些字符串中的任何一个都可以被视为幂等。同样,不变性意味着在状态被出售后不能发生变化。例如,
NSView
的subviews
方法返回一个不可变数组,从而确保调用者不会用内容玩游戏(甚至不希望能够)。在内部,NSView
可以选择返回包含子视图的[可能] NSMutableArray(因为它内部可变),并且类型转换为NSArray
意味着如果没有邪恶的强制转换或错误的编译器警告,调用者就无法操作内容。 (顺便说一句,这可能是也可能不是真正的实现——但这种模式在其他地方使用)。不变性还意味着可以进行枚举和/或遍历,而不会产生中间状态更改的风险。类似地,许多不可变类也是显式线程安全的;任意数量的线程可以同时读取不可变状态,通常不需要锁。
The immutable versions of the classes exist because an immutable object is, in and of itself, a unique identifier for a particular state. I.e. if you have an
NSArray
of 100NSString
instances, thatNSArray
instance can be treated as idempotent for any one of those strings.As well, the immutability means that a change cannot happen after the state has been vended. For example,
NSView
'ssubviews
method returns an immutable array, thus ensuring that the caller isn't going to play games with the contents (nor even expect to be able to). Internally,NSView
could choose to return the [likely] NSMutableArray that contains the subviews (since it is internally mutable) and the typecast toNSArray
means the caller can't manipulate the contents without an evil cast or bad compiler warning. (This may or may not actually be the real implementation, btw -- but this pattern is used elsewhere).Immutability also means that enumeration and/or traversal can be done without risk of a state change in the middle. Similarly, many immutable classes are also explicitly thread safe; any number of threads can simultaneously read the immutable state, often without need for a lock.
一般来说,对于 API 来说,不可变类将是线程安全的,因此您可以直接在后台线程中读取它,而不必担心内容会发生变化......
这对于内容可以移动的集合之类的东西来说更重要,您可能会在枚举它们的过程中。
In general for an API, an immutable class is going to be thread safe so you can read it directly in a background thread without worrying the contents will change...
That matters more for things like a collection where contents can shift and you might be in the middle of enumerating them.
该概念用于相关语言中。显着的区别是 objc 类型被命名为可变变体。类似的语言通常通过应用关键字来实现这一点,例如
const
。当然,其他相关语言也使用显式可变或不可变的类型。objc 消息传递不区分 const 和非 const,并且该语言不提供内置支持来确保对象的状态不会更改(尽管如果确实倾向于扩展编译器,那么这实际上并不是一个困难的添加)。所以这里也涉及到一些历史。
因此,类的约定是定义不变性与可变性,并提供区分可变性的变体。
多重抽象还引入了类型安全和意图。
是的。不变的对象可以进行多种优化。
某些情况包括:
某些情况包括:
copyWithZone:
或initWithType:
的实现可以返回保留的源,而不是深或浅的物理副本。它使编写清晰的接口变得更加容易。您可以保证并(尝试)限制某些事情。如果一切都是可变的,就会犯更多的错误和特殊情况。事实上,这种区别可能会完全改变我们编写 objc 库的方式:
因此,能够传递对象而不用担心客户端会在你背后更改,同时避免到处复制,这是很好的。
the concept is used in related langauges. the notable distinction is that the objc types are named mutable variants. similar langauges typically accomplish this via application of a keyword, such as
const
. of course, other related languages also use types which are explicitly mutable or immutable.objc messaging does not distinguish const and non-const, and the language does not provide builtin support for ensuring an object's state does not change (although it really would not be a difficult addition if one were really inclined to extend a compiler). so there's a little bit of history involved here too.
therefore, it's convention for the class to define immutability vs mutability, and to supply variants which distinguish mutability.
multiple abstractions also introduce type safety and intention.
yes. there are multiple optimizations an invariant object can make.
some cases include:
some cases include:
copyWithZone:
orinitWithType:
could return the source retained, rather than a deeep or shallow physical copy.it makes it easier to write clear interfaces. you can guarantee and (attempt to) restrict some things. if everything were mutable, there would be many more mistakes to make and special cases. in fact, the distinction could entirely change the way we approach writing objc libraries:
so it's nice to be able to pass objects around without worrying that the client will change behind your back, while avoiding copying all over the place.
基本上,当您知道数据结构是不可变的时,您可以围绕它进行许多优化。例如,如果数组是不可变的,则您可以在尝试添加对象时省略所有会“增长”数组的代码,并且可以简单地将不可变数组作为 id[] 的包装器。
Basically, when you know that a data structure is immutable, you can make many optimizations around that. For example, if an array is immutable, you can leave out all the code that would "grow" the array whenever you attempted to add an object, and you can simply have your immutable array be a wrapper around an
id[]
.除了上面提到的答案之外,一个区别是:
不可变对象通常是线程安全的。然而,可变对象不是线程安全的。
谢谢
Apart from the answers mentioned above one difference is :
Immutable objects are generally thread safe. Whereas, a Mutable objects are not thread safe.
thanks