我正在查看Apple的示例应用程序EditableDetailView,并注意到在其中一个控制器中,他们使用(非原子,复制)设置NSString属性的实例。何时使用副本而不是保留?这样他们可以在不影响现有数据的情况下制作独特的副本吗?
答案 0 :(得分:38)
是的,它可以在不影响现有数据的情况下制作独特的副本。合成的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
}
请注意,此处的操作顺序很重要 - 在自行分配的情况下,必须在释放旧值之前保留/复制新值。如果您先释放然后将属性分配给自己,则可能会意外释放该值。另请注意,如果旧值为nil
,则向其发送release
消息是可以的,因为明确允许向nil
对象发送消息并且不执行任何操作。
保留与复制的选择仅决定对象的属性是否与您设置的属性共享相同的值。请考虑以下代码:
// 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
答案 1 :(得分:3)
请记住,有一个NS Mutable 字符串。能够改变其他对象所拥有的字符串的内容(例如,通过删除其一半的字符)是非常糟糕的,特别是如果你没有意识到你正在影响另一个对象。因此,另一个对象可以自己制作副本。
你可能会说“好吧,为什么我不把它复制到那里之前复制它?”。也许对象需要一个可变的字符串,而你的字符串是不可变的。如果你必须先复制字符串,那么你必须在其文档或标题中查找它想要的字符串,然后进行正确的复制(每次)。通过这种方式,您只需说出other.string = myString
即可创建它想要的任何副本 - 您无需担心它。
答案 2 :(得分:0)
(出于某种原因,这篇文章出现在我试图回答的后续问题之上) 重新:
你的意思是我必须复制' 释放前的foo'对象 'foo'??但是如果我这是什么问题 在复制之前复制'foo' foo'??因为它们是两个不同的 对象我无法理解为什么 释放一个影响其他!!!!
大多数时候,你是对的。事实上,如果它们是两个独立的对象,那就不重要了。问题在于您可能将相同的对象重新分配给自身。如果你要说
[myObject setFoo: moof];
[myObject setFoo: moof];
然后第二次你这样做,你会在你复制它之前释放moof。在此期间,如果moof的保留计数变为零,则moof将被删除,并且您将无需在下一步中复制任何内容。 Foo现在是零。
这可能发生吗?可能比你想象的要多。例如,用户可能会点击两次“更新”按钮。
我希望这是可以理解和有用的。