Objective C 中 NSArray、NSDictionary 等类的可变和不可变版本背后的逻辑是什么?

发布于 2024-11-18 10:54:26 字数 106 浏览 2 评论 0原文

为什么 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

漫雪独思 2024-11-25 10:54:26

类的不可变版本之所以存在,是因为不可变对象本身就是特定状态的唯一标识符。也就是说,如果您有一个包含 100 个 NSString 实例的 NSArray,则该 NSArray 实例对于这些字符串中的任何一个都可以被视为幂等。

同样,不变性意味着在状态被出售后不能发生变化。例如,NSViewsubviews 方法返回一个不可变数组,从而确保调用者不会用内容玩游戏(甚至不希望能够)。在内部,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 100 NSString instances, that NSArray 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's subviews 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 to NSArray 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.

清君侧 2024-11-25 10:54:26

一般来说,对于 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.

最笨的告白 2024-11-25 10:54:26

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

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

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

objc 消息传递不区分 const 和非 const,并且该语言不提供内置支持来确保对象的状态不会更改(尽管如果确实倾向于扩展编译器,那么这实际上并不是一个困难的添加)。所以这里也涉及到一些历史。

因此,类的约定是定义不变性与可变性,并提供区分可变性的变体。

多重抽象还引入了类型安全和意图。

性能

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

某些情况包括:

  • 它可以缓存值,而不会多次计算它们。
  • 它可以对其数据使用精确的、不可调整大小的分配。
  • 它通常不需要任何特殊代码来进行多线程使用——许多不可变类型只会在构造/销毁期间发生变化。
  • 这些类型经常使用类簇。如果实现了类簇,那么专门的实现可以在内存、实现等方面提供显着差异。请考虑仅具有一个字符的不可变字符串与可变变体的不同之处。

内存管理

某些情况包括:

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

还是其他什么?

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

[[textField stringValue] appendString:@" Hz"];
[textField stateDidChange];

因此,能够传递对象而不用担心客户端会在你背后更改,同时避免到处复制,这是很好的。

Why do common collection classes in Objective C like NSString, NSArray, NSDictionary etc have a mutable as well as an immutable version.

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.

What is the logic behind defining them separately?

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.

Performance

yes. there are multiple optimizations an invariant object can make.

some cases include:

  • it could cache values, never computing them more than once.
  • it could use exact, nonresizable allocations for its data.
  • it often does not need any special code for multithreaded use -- many immutable types will only mutate during construction/destruction.
  • these types often use class clusters. if a class cluster is implemented, then specialized implementations can provide significant differences in memory, implementation, etc. consider how an immutable string with exactly one character could differ from a mutable variant.

memory management

some cases include:

  • immutable types could share their immutable contents.
  • they may also reduce allocations. for example, an implementation of copyWithZone: or initWithType: could return the source retained, rather than a deeep or shallow physical copy.

or anything else?

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:

[[textField stringValue] appendString:@" Hz"];
[textField stateDidChange];

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.

枯寂 2024-11-25 10:54:26

基本上,当您知道数据结构是不可变的时,您可以围绕它进行许多优化。例如,如果数组是不可变的,则您可以在尝试添加对象时省略所有会“增长”数组的代码,并且可以简单地将不可变数组作为 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[].

給妳壹絲溫柔 2024-11-25 10:54:26

除了上面提到的答案之外,一个区别是:
不可变对象通常是线程安全的。然而,可变对象不是线程安全的。

谢谢

Apart from the answers mentioned above one difference is :
Immutable objects are generally thread safe. Whereas, a Mutable objects are not thread safe.

thanks

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文