【问题标题】:Objective-C 101 (retain vs assign) NSStringObjective-C 101(保留与分配)NSString
【发布时间】:2010-11-25 16:55:32
【问题描述】:

101 题

假设我正在制作汽车数据库 每个汽车对象定义为:

#import <UIKit/UIKit.h>

@interface Car:NSObject{
    NSString *name;
}

@property(nonatomic, retain) NSString *name;

为什么是@property(nonatomic, retain) NSString *name; 而不是@property(nonatomic, assign) NSString *name;

我知道assign 不会像retain 那样增加引用计数器。但是为什么要使用retain,因为nametodo 对象的成员,它的范围是它自己。

其他外部函数也不会修改它。

【问题讨论】:

  • 但是为什么呢?请添加原因!
  • 简单:一个 NSMutableString 是一个 NSString。如果有人向您传递了一个您保留的可变字符串,那么他们可以在之后更改它。而且由于您的属性是 NSString 类型,因此您可能不会期待这种行为。总的来说,不可变类通过调用自身的 retain 来实现 -copy,所以它(通常)不会花费你任何内存,除非你真的需要那个内存。
  • @ipmcc readonly 属性(@property (nonatomic, retain/assign/copy, readonly) NSString *myString;)呢,是retaincopy 还是assign 那些更好?
  • 使用只读属性,retain/copy/assign 对外部调用者没有影响,但仍应准确反映您如何在内部处理类的基础值。如果您使用 ARC 和 @synthesize 创建 iVar,这一点很重要,因为编译器将使用您的属性声明来指示您希望 ARC 在自动处理保留/释放时如何处理该值。
  • @ipmcc:这并不完全正确。我将不得不再次验证它,但 IIRC 如果分配了只读对象属性,则 getter 只返回 iVar 的值,如果它是保留或复制,则 getter 将 iVar 的值返回为[[... retain] autorelease],可以是如果您曾经在代码中以某种方式替换 iVar 的值,这将是一个重要的区别。

标签: ios objective-c iphone nsstring retain


【解决方案1】:

如果没有retain,则无法保证您设置nameNSString* 将比赋值语句本身的寿命更长。通过为合成设置器使用retain 属性,您可以让它告诉内存管理系统至少还有一个对象对保留NSString* 感兴趣。

【讨论】:

  • 好的...是的,我想我有点明白你的意思了。请详细告诉我你的意思。
  • 因为,如果它对于retain方法是有效的,为什么不是对于assign语句
  • retain 确保它会保持活着,而对于 assign,则不能保证这一点。保留意味着您拥有该对象,只要您拥有它,它就不会被破坏。分配给你没有这样的保证。
  • 啊,很好的答案。但是为什么不将它用于其他声明,例如 NSInteger 类型。 @property(nonatomic, retain) NSInteger *name;
  • @qstar: NSInteger 不是对象。
【解决方案2】:

Objective-C 中没有“对象的范围”这样的东西。范围规则与对象的生命周期无关——保留计数就是一切。

您通常需要声明对实例变量的所有权。见the Objective-C memory management rules。使用retain 属性,您的属性设置者声明新值的所有权并放弃旧值的所有权。使用assign 属性,周围的代码必须这样做,这在职责和关注点分离方面同样混乱。使用 assign 属性的原因是您无法保留该值(例如 BOOL 或 NSRect 等非对象类型),或者保留它会导致不必要的副作用。

顺便说一下,在 NSString 的情况下,正确的属性类型通常是 copy。这样,如果有人传入 NSMutableString(这是有效的——它 一种 NSString),它就不会从你下面改变。

【讨论】:

  • 对于所有具有可变变体的类,您应该使用复制而不是保留。例如。 NSAArray、NSSet、NSDictionary、NSData、NSCharacterSet、NSIndexSet 和 NSString。
  • 根据经验,所有具有对象引用的属性都应使用复制或保留,但有一个例外;分配委托以避免循环引用。
  • @Matt:Efreedom 只有一些 SO 问题的副本,我建议改为链接到 original SO question
  • @Peylow:不只是代表;任何不是拥有关系的东西都应该使用assign 而不是copyretain。对象图下的路径应该是拥有的;图上的路径(包括在内)应该是非拥有的。否则,您将创建循环引用,而在圈子中没有委托。
  • 从技术上讲,我不会说在 Objective-C 中没有对象生命周期范围之类的东西。我想说唯一的作用域结束是自动释放池的清理,它发生在主运行循环中,而不是任何 Objective-C 代码的中间。但也许这有点太技术化了。 ;-)
【解决方案3】:

对于那些正在寻找它的人,Apple 关于属性属性的文档是here

【讨论】:

  • 该链接不再可用。
【解决方案4】:

如果你的班级得到了这个字符串对象,然后它又从它下面消失了,那会很不幸吗?你知道吗,就像你的班级第二次提到那个对象一样,它已经被另一个对象释放了?

这就是您要使用retain setter 语义的原因。

【讨论】:

  • 好的。那么为什么你会使用retain
  • 如果您正在创建 .delegate 属性,则委托可能会保留您。如果您保留它,您将创建一个依赖循环,这将导致两个对象都不会被释放。当然对于 ARC,这个问题已经过时了(我们现在使用“弱”和“强”来暗示类似的东西)。
  • @DanRay 仅当对象 B(已保留对象 A 的委托)在对象 A 的 dealloc 中释放时,对象才会被释放。
【解决方案5】:

别忘了通过

self.name = something;

因为

name = something;

不会关心生成的setter/getter方法,而是直接赋值。

【讨论】:

  • 谢谢,这非常重要!遵循最佳答案中的建议仍然没有保留价值。很重要的事self.name = ...
【解决方案6】:

self. 在:

self.name = something;

很重要!没有它,您将直接访问变量并绕过 setter。

较旧的样式(如果我错了,请纠正我)是:

[self setName:something];

无论如何,这个符号是我在NSStrings 上寻找合适的@properties 时真正需要的(听起来有点熟悉的)建议。谢谢阿克塞尔。

【讨论】:

  • 这是一个非常好的信息@jem。第一次,觉得太过分了(对比Java中的this
【解决方案7】:

Google 的 Objective-C Style Guide 很好地涵盖了这一点:

采用 NSString 的 Setter 应始终复制它接受的字符串。 永远不要只保留字符串。这样可以避免来电者在您不知情的情况下更改它。不要因为你接受一个 NSString 就假设它实际上不是一个 NSMutableString。

【讨论】:

    【解决方案8】:

    看了这么多文章、SO贴,做了demo app来检查Variable属性属性,我决定把所有属性信息放在一起

    1. 原子//默认
    2. 非原子
    3. strong=retain //默认
    4. weak= unsafe_unretained
    5. 保留
    6. 赋值 //默认
    7. unsafe_unretained
    8. 复制
    9. 只读
    10. 读写 //默认

    所以下面是详细的文章链接,您可以在其中找到上述所有属性,这将极大地帮助您。 非常感谢所有在这里给出最佳答案的人!

    Variable property attributes or Modifiers in iOS

    1. 保留 = 强
      • 它被保留,旧值被释放并被分配
      • retain 指定应在分配时发送新值 -retain 并发送旧值 -release
      • 保持与强相同。
      • 苹果说如果你写保留它会自动转换/只像强一样工作。
      • 像“alloc”这样的方法包含一个隐含的“retain”

    例子:

    @property (nonatomic, retain) NSString *name;
    
    @synthesize name;
    
    1. 分配
      • assign 是默认值,只是执行变量赋值
      • assign 是一个属性属性,它告诉编译器如何综合属性的 setter 实现
      • 我会将 assign 用于 C 原始属性,将 weak 用于对 Objective-C 对象的弱引用。

    例子:

    @property (nonatomic, assign) NSString *address;
    
    @synthesize address;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-07
      • 2013-02-18
      • 1970-01-01
      • 2012-02-14
      • 1970-01-01
      • 1970-01-01
      • 2010-11-24
      • 1970-01-01
      相关资源
      最近更新 更多