-copy 什么时候返回可变对象?

发布于 2024-12-01 19:29:15 字数 1479 浏览 2 评论 0原文

我在 Cocoa 和 Objective C:启动并运行中读到 -copy 将始终返回不可变对象,而 -mutableCopy 将始终返回可变对象:

重要的是要知道在可变对象上调用 -copy 会返回不可变对象 版本。如果你想复制一个可变对象并在新版本中保持可变性, 您必须在原始文件上调用 -mutableCopy 。不过,这很有用,因为如果你想要 要“冻结”一个可变对象,您只需对其调用 -copy 即可。

所以我有这样的事情:

NSMutableURLRequest *req = [[NSMutableURLRequest alloc] init];
NSLog( @"%@", [req className] );               // NSMutableURLRequest
NSLog( @"%@", [[req copy] className] );        // NSMutableURLRequest
NSLog( @"%@", [[req mutableCopy] className] ); // NSMutableURLRequest

根据这个 以前的答案

你不能依赖复制的结果是可变的!复制 NSMutableArray 可能 返回一个 NSMutableArray ,因为那是原始类,但复制任意 NSArray 实例不会。

这似乎与 NSURLRequest 有点隔离,因为 NSArray 按预期行事:

NSArray *arr = [[NSMutableArray alloc] init];
NSLog( @"%@", [arr className] );                 // __NSArrayM
NSLog( @"%@", [[arr copy] className] );          // __NSAraryI
NSLog( @"%@", [[array mutableCopy] className] ); // __NSArrayM

所以...

  1. When does -copy return an immutable object (as预期)以及何时返回可变对象?
  2. 如何达到获得拒绝“冻结”的可变对象的“冻结”副本的预期效果?

I read in Cocoa and Objective C: Up and Running that -copy will always return an immutable object and -mutableCopy will always return a mutable object:

It’s important to know that calling -copy on a mutable object returns an immutable
version. If you want to copy a mutable object and maintain mutability in the new version,
you must call -mutableCopy on the original. This is useful, though, because if you want
to “freeze” a mutable object, you can just call -copy on it.

So I have something like this:

NSMutableURLRequest *req = [[NSMutableURLRequest alloc] init];
NSLog( @"%@", [req className] );               // NSMutableURLRequest
NSLog( @"%@", [[req copy] className] );        // NSMutableURLRequest
NSLog( @"%@", [[req mutableCopy] className] ); // NSMutableURLRequest

According to this previous answer:

You cannot depend on the result of copy to be mutable! Copying an NSMutableArray may
return an NSMutableArray, since that's the original class, but copying any arbitrary
NSArray instance would not.

This seems to be somewhat isolated to NSURLRequest, since NSArray acts as intended:

NSArray *arr = [[NSMutableArray alloc] init];
NSLog( @"%@", [arr className] );                 // __NSArrayM
NSLog( @"%@", [[arr copy] className] );          // __NSAraryI
NSLog( @"%@", [[array mutableCopy] className] ); // __NSArrayM

So...

  1. When does -copy return an immutable object (as expected) and when does it return a mutable object?
  2. How do I achieve the intended effect of getting a "frozen" copy of a mutable object that refuses to be "frozen"?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(4

じее 2024-12-08 19:29:16

将对象转变为可变对象的最佳方法是使用可变“构造函数”。例如:

NSArray* array = ...;
NSMutableArray* mutableArray = [NSMutableArray arrayWithArray: array];

Copy 用于制作对象的副本。不改变它的可变性。

The best way to turn an object into an mutable one is to use the mutable 'constructor'. Like for example:

NSArray* array = ...;
NSMutableArray* mutableArray = [NSMutableArray arrayWithArray: array];

Copy is used to make a copy of an object. Not to change it's mutability.

素年丶 2024-12-08 19:29:15

我认为你已经发现了文档和现实之间的巨大裂痕。

NSCopying 协议文档声称:

如果“不可变与可变”的考虑适用于接收对象,则返回的副本是不可变的;否则副本的确切性质由类决定。

但在某些情况下,这显然是错误的,正如您在示例中所示的那样(并且我已通过该文档页面向他们发送了有关此问题的反馈)。

但是(#2)在我看来,这实际上并不重要,你不应该关心。

-copy 的要点是它将返回一个您可以使用的对象并保证其行为独立于原始对象。这意味着如果您有一个可变对象,请复制它,并更改原始物体,复制后看不到效果。 (在某些情况下,我认为这意味着 -copy 可以优化为不执行任何操作,因为如果对象是不可变的,那么它首先就无法更改。我对此可能是错的。 (我现在想知道因此对字典键有什么影响,但这是一个单独的主题...))

正如您所见,在某些情况下,新对象实际上可能是一个可变类(即使文档告诉我们它不会)。但只要您不依赖它的可变性(为什么要这样做?),那就没关系。

你应该做什么? 始终将-copy的结果视为不可变,就这么简单。

I think you've uncovered a great rift between documentation and reality.

The NSCopying protocol documentation claims:

The copy returned is immutable if the consideration “immutable vs. mutable” applies to the receiving object; otherwise the exact nature of the copy is determined by the class.

But this is clearly wrong in some cases, as you've shown in your examples (and I've sent feedback to them about this via that documentation page).

But(#2) in my opinion, it doesn't actually matter and you shouldn't care.

The point of -copy is that it will return an object you can use with the guarantee that it will behave independently of the original. This means if you have a mutable object, -copy it, and change the original object, the copy will not see the effect. (In some cases, I think this means that -copy can be optimized to do nothing, because if the object is immutable it can't be changed in the first place. I may be wrong about this. (I'm now wondering what the implications are for dictionary keys because of this, but that's a separate topic...))

As you've seen, in some cases the new object may actually be of a mutable class (even if the documentation tells us it won't). But as long as you don't rely on it being mutable (why would you?), it doesn't matter.

What should you do? Always treat the result of -copy as immutable, simple as that.

笑脸一如从前 2024-12-08 19:29:15

1) -copy 何时返回不可变对象(如预期)以及何时返回可变对象?

您应该始终将其视为不可变的变体。不应使用返回类型的可变接口。除了优化之外,答案应该不重要,并且应该被视为实现细节,除非有记录。

明显的例子:由于多种原因,objc 类集群和类设计可能很复杂。返回可变副本可能只是为了方便。

2)如何达到获得拒绝“冻结”的可变对象的“冻结”副本的预期效果?

使用不可变类的复制构造函数是一个好方法(类似于St3fan的答案)。就像copy一样,它不是一个保证。

我能想到的为什么你想要强制执行这种行为的唯一原因是为了性能或强制执行受限的接口(除非它是学术性的)。如果您想要性能或受限接口,那么您可以简单地封装该类型的实例,该实例在创建时复制并仅公开不可变接口。然后你通过保留来实现复制(如果这是你的意图)。

或者,您可以编写自己的子类并实现自己的副本变体。

最后的手段:许多可可可变/不可变类都是纯粹的接口 - 如果您需要确保特定的行为,您可以编写自己的子类 - 但这是很不寻常的。

也许更好地描述为什么应该强制执行这一点会很好 - 现有的实现对于绝大多数开发人员/用户来说工作得很好。

1) When does -copy return an immutable object (as expected) and when does it return a mutable object?

you should always treat it as the immutable variant. the mutable interface of the returned type should not be used. apart from optimizations, the answer should not matter and should be considered an implementation detail unless documented.

the obvious case: for a number of reasons, objc class clusters and class designs can be complex. returning a mutable copy could simply be for convenience.

2) How do I achieve the intended effect of getting a "frozen" copy of a mutable object that refuses to be "frozen"?

using the copy constructor of the immutable class is a good way (similar to St3fan's answer). like copy, it's not a guarantee.

the only reason i can think of as to why you would want to enforce this behaviour is for performance or to enforce a restricted interface (unless it's academic). if you want performance or a restricted interface, then you can simply encapsulate an instance of the type which copies on creation and exposes only the immutable interface. then you implement copy via retain (if that's your intent).

alternatively, you can write your own subclass and implement your own variant of copy.

final resort: many of the cocoa mutable/immutable classes are purely interface - you could write your own subclass if you need to ensure a particular behaviour -- but that's quite unusual.

perhaps a better description of why this should be enforced would be good - the existing implementations work just fine for the vast majority of developers/uses.

明月松间行 2024-12-08 19:29:15

请记住,不存在单一的复制实现——每个类都实现自己的。而且,众所周知,Objective C 运行时的实现有些地方有点“松散”。所以我认为我们可以说大部分 copy 返回一个不可变的版本,但也存在一些例外。

(顺便说一句,这是做什么的:

NSArray *arr = [[NSMutable array] init];

?)

Bear in mind that there is not one copy implementation -- each class implements its own. And, as we all know, the implementation of the Objective C runtime is a little "loosey goosey" in spots. So I think we can say that mostly copy returns an immutable version, but some exceptions exist.

(BTW, what does this do:

NSArray *arr = [[NSMutable array] init];

?)

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