Objective-C:为什么使用非 NSMutable 对象?
为什么有人应该使用 Objective-C 中数据结构的非 NSMutable 等价物?当您需要一个不应该被修改的 const
对象时?使用非 NSMutable 类是否会以任何方式提高性能?还有其他情况吗?
Why should someone ever use the non-NSMutable equivalents of the data structures in Objective-C? When it's a situation when you need a const
object that should not be modified? Does using non-NSMutable classes improve performance in any way? Any other situations?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我脑海中浮现出两个主要原因:
您还倾向于看到支持原始值的固有保留的论点是有用的,特别是在语义和设计模式方面。
不可变类本身的效率并不高,但有一个例外——例如,如果您获取可变数组的不可变副本,那么就很清楚需要多少存储空间以及可以分配多少存储空间。由于内存分配需要时间,因此可变集合倾向于保留一些备用存储,因为它们无法预测它们将如何增长。
The two main reasons off the top of my head:
You also tend to see arguments in favour of the inherent preservation of the original value being useful, especially in terms of semantics and design patterns.
Immutable classes don't tend to be much more efficient in and of themselves with one exception — if you take an immutable copy of a mutable array, for example, then it's clear exactly how much storage is needed and exactly that much can be allocated. Because memory allocation costs time, mutable collections tend to keep some spare storage around because they can't predict how they're going to grow.
const
与非可变对象没有直接关系;我对后者比较熟悉,所以我就讲这个。不可变对象就像一个保留。想象一下,您在一家繁忙的餐厅工作,该餐厅只接受预订——所有客人都必须预订。当有人打电话预订 6 点的 8 人座位时,您知道您将在 6 点等待 8 人。当然,这可以让事情变得可预测。您知道要布置一张可容纳八人的桌子(使用多于一张桌子是没有意义的,尤其是在繁忙的餐厅)。你通知厨房并告诉他们六点过后几分钟会有八份订单(好吧,也许你不会,但你也可以)。这样一来,一切都进展顺利,没有任何耽搁。当八个人在六点准时到达时(因为这个世界上的每个人都非常准时),你带领他们直接到座位上,他们点餐并享用餐点。没有任何问题。
如果预订时没有指定人数或时间,就会出现问题。想象一下有人打电话告诉你期待一群人共进晚餐。在这种情况下,您没有任何信息。一个团体可以是一对约会的情侣、一个四人家庭,或者是参加公司活动的两打人。他们可能会迟到,因为他们正在看电影,可能会很早到达,因为他们有一个年幼的孩子,或者在不同的时间到达,因为不可能协调每个人。在这种情况下,您将不得不为每个人寻找座位,厨房可能会突然被大量订单淹没。或者你可能已经封锁了许多座位,厨房可能会发现自己无事可做。在任何一种情况下,如果你高估或低估,就会出现延误并失去潜力。什么事情都可能发生。
在这个比喻中,餐厅是运行时系统,预订是对象。在第一个场景中,您有一个不可变的对象,例如 NSArray。系统知道它将保存多少数据、有多少元素,以及在运行时它们是什么类型。系统知道大小不会改变,因此它可以优化 RAM 以绕过该阵列,而不留下任何预防位。一切都进展顺利,因为一切都是已知的。
相比之下,NSMutableArray 是一无所知的。用户可能会添加更多元素,因此系统必须努力寻找更多 RAM,而不是使用相同的时钟周期来处理某些操作;用户可能会用较大的元素替换中间的元素,从而必须偏移所有后面的元素,这涉及复制之后的所有元素。在某些情况下,它可能涉及将数组或字符串或其他任何内容的所有元素复制到新位置,这是一个(可能)昂贵的操作。这会带来显着的性能开销,尤其是当您使用大量它们时。例如,在 Java 中,连接字符串涉及将整个现有字符串复制到新的内存位置,并让垃圾收集器处理旧字符串。
另一个令人信服的原因是,您使更改数据变得更加困难。 (该类的)用户必须显式地创建一个可变副本,这有助于确保他们知道自己在做什么。这个优点在多线程中尤其显着——您不想将可变对象传递给在后台线程上运行的对象,因为前台线程(或任何其他线程)可能会修改该对象,因为它正在被后台线程修改。原始线程,导致非常有趣的结果。
const
is not directly related to non-mutable objects; I'm more familiar with the latter, so that's what I'll talk about.A non-mutable object is like a reservation. Imagine that you work at a busy restaurant that only works on a reservation basis—all guests must make a reservation. When someone calls and makes a reservation for eight people at six, you know that you'll be expecting eight people at 6. Of course, this keeps things predictable. You know to set out one table that can sit eight people (it wouldn't make sense to use more than one table, especially at a busy restaurant). You notify the kitchen and tell them to expect eight orders a few minutes after six (okay, maybe you won't, but you might as well). In this way, everything runs smoothly and there are no delays. When the party of eight arrives promptly at six (because everyone in this world is perfectly punctual), you lead them right over to their seats, they order, and enjoy their meal. No problems whatsoever.
A problem arises if the reservation never specifies the number of people or the time. Imagine someone calls and tells you to expect a group of people for dinner. In this case, you have no information. A group could be a couple on a date, a four-person family, or two dozen people for a corporate function. They might arrive late because they were at a movie, really early because they have a young child, or at different times because it was impossible to coordinate everyone. In this case, you would have to scramble to find seating for everyone and the kitchens might suddenly be swamped with a large number of orders. Or you could have blocked off to many seats and the kitchen might find itself with nothing to do. In either case, where you over-estimate or under-estimate, there are delays and lost potential. Anything could happen.
In this metaphor, the restaurant would be the runtime system, and the reservations are the objects. In the first scenario, you have a non-mutable object, like an
NSArray
. The system knows how much data it'll hold, how many elements there are, and by runtime, what type they are. The system knows that the size won't change, so it can optimize RAM to go around that array, without leaving any precautionary bits. Everything runs smoothly because everything is known.By contrast, nothing is known with an
NSMutableArray.
The user might add more elements, so the system has to scramble to find more RAM, rather than using those same clock cycles to crunch some operation; the user might replace an element in the middle with a larger one, having to offset all the later elements—which involves copying all tho elements after. In certain cases, it could involve copying all the elements of the array or string or whatever to a new location, a (potentially) expensive operation. This can impart a significant performance overhead, especially when you use a lot of them. In Java for example, concatenating a string involves copying the entire existing string to a new memory location, and leaving the garbage collector to deal with the old string.Another compelling reason is that you make it a bit harder to change the data. Users (of the class) have to explicitly make a mutable copy, which helps to ensure that they know what they're doing. This advantage is particularly notable with multiple threads—you don't want to pass a mutable object to something that's running on a background thread, because the foreground thread (or any other) could then be modifying the object, as it's being modified by the original thread, leading to very interesting results.