【问题标题】:NSString @property, using copy instead of retainNSString @property,使用复制而不是保留
【发布时间】:2010-10-09 21:36:59
【问题描述】:

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

【问题讨论】:

  • 建议对属于具有可变/不可变对的类集群的一部分的类使用复制;比如NSString/NSMutableStringNSArray/NSMutableArrayNSDictionary/NSMutableDictionaryNSSet/NSMutableSet,见@Abizern的回答HERE

标签: iphone objective-c cocoa cocoa-touch


【解决方案1】:

是的,这样它就可以在不影响现有数据的情况下制作唯一的副本。合成的 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

【讨论】:

  • 您的最后一行可能有错字。其中 //someObject.foo 不...应该是 //someObject.bar 不
  • 为了能够在自定义 Class 对象上调用 copy,您必须重写 copyWithZone: 方法。
【解决方案2】:

记住有一个 NSMutableString。能够改变某个其他对象拥有的字符串的内容(例如,通过删除其一半字符)真的很糟糕,特别是如果您没有意识到您正在影响另一个对象。因此,最好让其他对象制作自己的副本。

您可能会说“好吧,我为什么不在分配字符串之前复制它呢?”。也许对象想要一个可变字符串,而你的字符串是不可变的。如果您必须先复制字符串,那么您必须在其文档或标题中查找它想要的字符串类型,然后制作正确的副本(每次)。这样一来,您只需说 other.string = myString,它就会制作它想要的任何类型的副本——您不必担心。

【讨论】:

    【解决方案3】:

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

    你的意思是我必须复制' 释放前的 foo' 对象 'foo'??但是如果我有什么问题 在复制 'the 之前释放 'foo' foo'??因为它们是两个不同的 对象我不明白为什么 释放一个影响另一个!!!!

    大多数时候,你是对的。事实上,如果它们是两个独立的对象,那就没关系了。问题在于您将相同的对象分配回自身的可能性。如果你说

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

    然后你第二次这样做,你会在复制之前释放 moof。在此期间,如果 moof 的保留计数变为零,则可能会删除 moof,并且在接下来的步骤中您将没有任何内容可复制。 Foo 现在为零。

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

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

    【讨论】:

    • Stack Overflow 是一个问答网站,而不是论坛。默认情况下,答案和您要回答的“问题”均按投票排序。您的答案为 0,而另一个答案(现已删除)最终为 -3,因此您的答案似乎更高(对于我们这些有足够业力的人来说,根本无法看到另一个答案)。正确的方法是评论另一个答案,但这需要 50 个声望点,而你没有。 (另外,您的答案太深且格式太丰富,无法放入评论中。)您的情况没有正确的方法。
    猜你喜欢
    • 2012-07-09
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多