NSString @property,使用copy而不是retain

时间:2022-04-25 20:00:19

I'm looking over Apple's sample application EditableDetailView, and noticed that in one of their controllers, they're setting an instance of NSString property with (nonatomic, copy). When would one use copy instead of retain? Is this so they can make a unique copy without affecting the existing data?

我查看了苹果的示例应用程序EditableDetailView,注意到在其中一个控制器中,他们正在用(非原子的,复制的)设置一个NSString属性的实例。什么时候使用复制而不是保留?这样他们就可以在不影响现有数据的情况下复制唯一的副本了吗?

3 个解决方案

#1


38  

Yes, it's so that it can make a unique copy without affecting the existing data. The synthesized setters essentially look like this:

是的,它是为了在不影响现有数据的情况下复制唯一的副本。合成的setter基本上是这样的:

// For @synthesize(nonatomic, retain) foo:
- (void) setFoo(NSFoo *theFoo)
{
    [theFoo retain];  // retain new value
    [foo release];    // release old value, if any
    foo = theFoo;     // assign new value
}

// For @synthesize(nonatomic, copy) foo:
- (void) setFoo(NSFoo *theFoo)
{
    NSFoo* newFoo = [theFoo copy];  // make copy
    [foo release];  // release old value, if any
    foo = newFoo;   // assign new value
}

Note the order of operations here is important - the new value must be retained/copied before the old value is released, in case of self-assignment. If you released first and then assigned the property to itself, you might deallocate the value by accident. Also note that if the old value is nil, sending it a release message is ok, since sending a message to a nil object is explicitly allowed and does nothing.

注意这里的操作顺序很重要——在释放旧值之前,必须保留/复制新值,以备自赋。如果您首先释放该属性,然后将其分配给自己,那么您可能会意外地释放该值。还要注意,如果旧值为nil,那么向它发送发布消息是可以的,因为显式地允许向nil对象发送消息,而且什么都不做。

The choice of retaining versus copying just determines whether or not the object's property shares the same value with what you're setting it to. Consider the following code:

保留与复制的选择决定了对象的属性是否与您所设置的属性共享相同的值。考虑下面的代码:

// suppose the 'foo' property is declared 'retain' and the 'bar' property is
// declared 'copy'
NSFoo *foo = ...;
NSBar *bar = ...;
someObject.foo = foo;
someObject.bar = bar;
[foo changeInternalState];  // someObject.foo also changes, since it's the same object
[bar changeInternalState];  // someObject.bar does NOT change, since it's a copy

#2


3  

Remember that there is an NSMutableString. It would be really bad to be able to mutate the contents of a string that some other object owns (say, by deleting half its characters), especially if you don't realize you're affecting another object. Therefore, it's nice for the other object to make its own copy.

记住有一个NSMutableString。如果能够修改其他对象拥有的字符串的内容(例如,删除其一半的字符),那就太糟糕了,尤其是当您没有意识到您正在影响另一个对象时。因此,另一个对象创建自己的副本是很好的。

You may say “well, why don't I just copy the string before assigning it there?”. Maybe the object wants a mutable string and yours is immutable. If you have to copy the string first, then you have to look up which kind of string it wants in its documentation or header, then make the right kind of copy (every time). This way, you just say other.string = myString and it makes whatever kind of copy it wants—you don't have to worry about it.

你可能会说,为什么我不把字符串复制到那里呢?也许对象需要一个可变字符串,而您的字符串是不可变的。如果您必须首先复制字符串,那么您必须在文档或header中查找它想要哪种类型的字符串,然后(每次)进行正确的复制。这样的话,你就说别人。string = myString它可以复制它想要的任何类型-你不用担心它。

#3


0  

(For some reason, this post is appearing above the follow-up question I am trying to answer) Re:

(由于某些原因,这篇文章出现在我试图回答的后续问题之上)Re:

did you mean that i have to copy 'the foo' object before releasing 'foo'??but whats the problem if i relaese 'foo' before copying 'the foo'??because they are two different object i can't understand why releasing one affect other!!!!

你是说在释放foo之前我必须复制foo对象吗?但是,如果我在复制foo之前先休息一下,会有什么问题呢?因为他们是两个不同的物体,我不明白为什么释放一个影响另一个!!!

Most of the time, you are correct. If they are, in fact, two separate objects, it won't matter. The problem lies in the possibility that you are assigning the same object back into itself. If you were to say

大多数时候,你是对的。如果它们实际上是两个独立的对象,那就不重要了。问题在于您可能将相同的对象重新分配给它自己。如果你要说

[myObject setFoo: moof];
[myObject setFoo: moof];

Then the second time you did it, you would release moof before you copied it. In the intervening moment, it is possible that if moof's retain count went to zero then moof would be deleted, and you would have nothing to copy in the following step. Foo would now be nil.

然后,在第二次复制之前,您将发布moof。在这段时间内,如果moof的retain count变为0,那么moof将被删除,在接下来的步骤中您将没有什么要复制的。Foo现在是nil。

Is this likely to happen? Probably more than you might think. There are certainly times when the user might click on an "update" button twice, for example.

这有可能发生吗?可能比你想象的要多。当然,有时用户可能会两次点击“更新”按钮。

I hope this is understandable and helpful.

我希望这是可以理解和帮助的。

#1


38  

Yes, it's so that it can make a unique copy without affecting the existing data. The synthesized setters essentially look like this:

是的,它是为了在不影响现有数据的情况下复制唯一的副本。合成的setter基本上是这样的:

// For @synthesize(nonatomic, retain) foo:
- (void) setFoo(NSFoo *theFoo)
{
    [theFoo retain];  // retain new value
    [foo release];    // release old value, if any
    foo = theFoo;     // assign new value
}

// For @synthesize(nonatomic, copy) foo:
- (void) setFoo(NSFoo *theFoo)
{
    NSFoo* newFoo = [theFoo copy];  // make copy
    [foo release];  // release old value, if any
    foo = newFoo;   // assign new value
}

Note the order of operations here is important - the new value must be retained/copied before the old value is released, in case of self-assignment. If you released first and then assigned the property to itself, you might deallocate the value by accident. Also note that if the old value is nil, sending it a release message is ok, since sending a message to a nil object is explicitly allowed and does nothing.

注意这里的操作顺序很重要——在释放旧值之前,必须保留/复制新值,以备自赋。如果您首先释放该属性,然后将其分配给自己,那么您可能会意外地释放该值。还要注意,如果旧值为nil,那么向它发送发布消息是可以的,因为显式地允许向nil对象发送消息,而且什么都不做。

The choice of retaining versus copying just determines whether or not the object's property shares the same value with what you're setting it to. Consider the following code:

保留与复制的选择决定了对象的属性是否与您所设置的属性共享相同的值。考虑下面的代码:

// suppose the 'foo' property is declared 'retain' and the 'bar' property is
// declared 'copy'
NSFoo *foo = ...;
NSBar *bar = ...;
someObject.foo = foo;
someObject.bar = bar;
[foo changeInternalState];  // someObject.foo also changes, since it's the same object
[bar changeInternalState];  // someObject.bar does NOT change, since it's a copy

#2


3  

Remember that there is an NSMutableString. It would be really bad to be able to mutate the contents of a string that some other object owns (say, by deleting half its characters), especially if you don't realize you're affecting another object. Therefore, it's nice for the other object to make its own copy.

记住有一个NSMutableString。如果能够修改其他对象拥有的字符串的内容(例如,删除其一半的字符),那就太糟糕了,尤其是当您没有意识到您正在影响另一个对象时。因此,另一个对象创建自己的副本是很好的。

You may say “well, why don't I just copy the string before assigning it there?”. Maybe the object wants a mutable string and yours is immutable. If you have to copy the string first, then you have to look up which kind of string it wants in its documentation or header, then make the right kind of copy (every time). This way, you just say other.string = myString and it makes whatever kind of copy it wants—you don't have to worry about it.

你可能会说,为什么我不把字符串复制到那里呢?也许对象需要一个可变字符串,而您的字符串是不可变的。如果您必须首先复制字符串,那么您必须在文档或header中查找它想要哪种类型的字符串,然后(每次)进行正确的复制。这样的话,你就说别人。string = myString它可以复制它想要的任何类型-你不用担心它。

#3


0  

(For some reason, this post is appearing above the follow-up question I am trying to answer) Re:

(由于某些原因,这篇文章出现在我试图回答的后续问题之上)Re:

did you mean that i have to copy 'the foo' object before releasing 'foo'??but whats the problem if i relaese 'foo' before copying 'the foo'??because they are two different object i can't understand why releasing one affect other!!!!

你是说在释放foo之前我必须复制foo对象吗?但是,如果我在复制foo之前先休息一下,会有什么问题呢?因为他们是两个不同的物体,我不明白为什么释放一个影响另一个!!!

Most of the time, you are correct. If they are, in fact, two separate objects, it won't matter. The problem lies in the possibility that you are assigning the same object back into itself. If you were to say

大多数时候,你是对的。如果它们实际上是两个独立的对象,那就不重要了。问题在于您可能将相同的对象重新分配给它自己。如果你要说

[myObject setFoo: moof];
[myObject setFoo: moof];

Then the second time you did it, you would release moof before you copied it. In the intervening moment, it is possible that if moof's retain count went to zero then moof would be deleted, and you would have nothing to copy in the following step. Foo would now be nil.

然后,在第二次复制之前,您将发布moof。在这段时间内,如果moof的retain count变为0,那么moof将被删除,在接下来的步骤中您将没有什么要复制的。Foo现在是nil。

Is this likely to happen? Probably more than you might think. There are certainly times when the user might click on an "update" button twice, for example.

这有可能发生吗?可能比你想象的要多。当然,有时用户可能会两次点击“更新”按钮。

I hope this is understandable and helpful.

我希望这是可以理解和帮助的。