【问题标题】:iphone - properties and instance variablesiphone - 属性和实例变量
【发布时间】:2012-01-18 16:28:51
【问题描述】:

假设我有这个代码...

foo.h

@interface Foo : NSObject {
    NSString *aString; // 1   
}

@property (nonatomic, retain) NSString *aString;

foo.m

@synthesize aString = _aString;


....

- (void)dealloc {
    [aString release];
    [super dealloc];
}

我的问题是:

  • 我真的需要在“1”中声明aString吗? (见代码)
  • 如果我正在合成 aString = _aString,我已经在创建一个实例 变量,对吧?
  • 如果我保留 foo.h (@property) 上的属性,为什么如果我在 dealloc 中释放 aString,Xcode 会报错?

谢谢。

【问题讨论】:

    标签: iphone objective-c ios properties


    【解决方案1】:

    您正在混淆属性和支持变量。 “aString”是您通过方法调用访问的属性(例如 [self aString])。 “_aString”是支持变量,您可以直接访问它(例如 _aString)。

    按顺序回答您的问题:

    • 没有。这是一个未使用的变量,因为您告诉编译器使用 _aString 作为变量。 (您实际上不需要在现代运行时声明任何一个。)

    • 是的,如我对第一个问题的回答所示。

    • 因为编译器希望您向对象发送消息,而“aString”未定义为书面形式。通常您会使用 [self aString] 来访问对象,但这是一种特殊情况:在 -dealloc 和 -initXYZ 中,由于潜在的副作用,您不使用访问器方法。切换到 [_aString release] 一切都会正常运行(除非你有 ARC,在这种情况下你根本不释放。

    【讨论】:

    • 啊,我明白了,字符串是真实东西的一种别名...:D ...谢谢。你的回答太完美了!!!!!!
    • 编译器在幕后为你做更多的事情。如果您想更好地了解属性,我为 cocoa-dev 邮件列表中的某个人写了一个详细的回复 (cocoabuilder.com/archive/cocoa/…)。
    【解决方案2】:

    对于您的@synthesize,实例变量(您的“1”)应该是NSString* _aString

    将 synthesize 与不同命名的变量一起使用的原因是,您始终使用 self.aString 来正确释放旧对象,而不是通过直接修改 aString 来意外覆盖指针。

    您是否启用了 ARC?如果是这样,这就是 Xcode 抱怨发布它的原因。

    【讨论】:

    • 不,我没有启用弧。这是一个针对 iOS 4.2 的项目。关于 _aString 在“1”上的声明,我同意这是合乎逻辑的,但为什么许多作者不这样做呢?我见过很多项目,这个人只是在@property 声明它并合成。
    【解决方案3】:

    按顺序回答您的问题:

    • 没有。我可能缺少某种“最佳实践”的原因,但@property 也会合成实例变量。
    • 当你声明aString = _aString时,你可以直接操作_aString而不访问合成的getter/setter(通过调用_aString)或者使用合成的getter/setter(通过调用self.aString) .
    • 您可能正在其他地方发布它,其他人过度发布它,或者您正在使用 ARC。对于NSStrings(以及其他具有现成可用的深层复制方法的简单对象),我发现最好使用@property (copy)_aString = [stringPassedToInit copy],这样您就是唯一处理字符串保留计数的人。如果您使用 ARC,则在大多数情况下无需担心保留/释放。

    【讨论】:

      【解决方案4】:

      不,您不再需要声明 ivars(我认为是 iOS 3 起)。您可以删除接口声明的整个 { ... } 部分,这不会有任何区别。

      之所以抱怨,是因为您的 ivar 被命名为 _aString,而不是 aString。你需要说

      [_aString release]
      

      改为。

      【讨论】:

      • 不,我没有使用 ARC。你的意思是我不需要为属性声明 ivars,对吧?我必须声明的其他 ivars...
      • 是的,如果你合成一个属性,你不需要为它声明ivar。您可以对所有内容使用属性,而根本不使用 ivars,这是最佳实践。如果您希望您的属性是私有的,请在您的 .m 文件中的私有接口中声明它们,而不是在您的 .h 文件中。
      【解决方案5】:

      答案:-

      我真的需要在 "1" 中声明 aString 吗? (见代码) - 现在从 iOS 4 开始,你不需要声明了。

      如果我正在合成 aString = _aString,我已经在创建一个实例变量,对吗? - 是的

      如果我保留 foo.h (@property) 上的属性,如果我在 dealloc 中释放 aString,为什么 Xcode 会抱怨? - 现在你需要使用这个 - self.aString = nil,这会小心的。

      【讨论】:

      • 错误答案。不要在 dealloc 中使用访问器 - 例如self.aString = 无。这可能会产生意想不到的后果。
      • 正确。永远不要在 dealloc 或 init 中使用访问器。
      • Why Downvote,而苹果的 Objective-C 2.0, p74 中也提到了这一点 - 但是,如果您使用现代运行时并合成实例变量,则无法直接访问实例变量,因此您必须调用访问器方法。你可以看看这个并告诉我我哪里错了。
      • 但是对于 iOS 4.0,如果我们不声明实例变量,那么如何访问呢?
      • 在 dealloc 中不使用访问器的原因是合理的(不要调用可能被子类覆盖的方法,如果在 dealloc 时执行会导致问题)而这样做的原因(因为你可以't access synthesis ivars directly) 显然是错误的。
      【解决方案6】:

      我的答案是:

      • 没有
      • 是的
      • 改用[_string release]

      【讨论】:

        猜你喜欢
        • 2011-09-07
        • 1970-01-01
        • 1970-01-01
        • 2016-03-14
        • 2010-10-17
        • 2011-09-01
        • 2010-12-05
        • 2010-10-23
        • 1970-01-01
        相关资源
        最近更新 更多