【问题标题】:Syntax for accessing instance variables? (Objective-C)访问实例变量的语法? (目标-C)
【发布时间】:2011-09-15 15:39:18
【问题描述】:

在 Objective-C 中访问实例变量的正确语法是什么?

假设我们有这个变量:

@interface thisInterface : UIViewController {
    NSMutableString *aString;
}

@property (nonatomic, retain) NSMutableString *aString;

它是合成的。

当我们想要访问它时,我们首先要分配和初始化它。用 Objective-C 编程大约一个月了,我已经看到了两种不同形式的语法。我见过人们只是简单地aString = [[NSMutableString alloc] initWithString:@"hi"],他们在那里分配字符串;我还看到人们以self.aString 开始它,然后他们继续初始化他们的ivar。我想我只是想弄清楚初始化实例变量的最正确方法是什么,因为在前一个示例中,我收到了 EXC_BAD_ACCESS 错误。但是,在添加 self. 之后,它并没有出现。

如果这是一个重复的问题,请原谅我,但是在阅读了一些关于 SO 的帖子后,这让我很好奇。我正在尝试使用 Objective-C 学习正确的语法,因为我更喜欢正确而不是草率。

【问题讨论】:

  • 在处理字符串时应该使用 Copy 而不是 Retain。

标签: iphone objective-c ios ivar


【解决方案1】:

如果您在 .m 文件中声明了一个属性并@synthesize 它,您只需像这样设置它:

self.aString = @"hi"; // or [[NSMutableString alloc] initWithString:@"hi"];

使用self.varName 可以利用您的属性声明的实际作用——它处理新值的保留(因为您的属性具有retain 属性),为您释放旧值等。

如果你这样做:

aString = someValue;

...您可能会泄漏 aString 中的原始值,因为不使用 self.aString 您是直接访问变量而不是通过属性访问变量。

【讨论】:

  • 这正是我想要的!我认为这与保留财产有关。所以当直接给 ivar 赋值时,我们不会释放旧值(因为这就是 retain 属性所做的,对吧)?这最终会导致一些泄漏。我只是想在开始分析我的代码之前确保它是正确的。
  • 是的,如果直接修改 ivar,就会绕过属性的合成访问器代码。这可能会导致泄漏、提前释放等。不好的事情。一般来说,这不是你想要的。
  • 你确实意识到 self.aString = [[NSMutableString alloc] initWithString:@"hi"];如果属性具有保留属性,则为泄漏......
  • 我明白了。非常感谢,您的解释简明易懂! :) 我同意@Simon Lee,因为它会被保留两次。
  • 是的-@Simon Lee 适合您分配而不是使用自动释放的便捷方法。
【解决方案2】:

注意self->varNameself.varName之间的区别

首先是指针访问。第二个是property 访问。

为什么这很重要?指针访问是直接的。另一方面,属性访问使用 getter 和 setter(无论是否@synthesized)。此外,为方便起见,@synthesized 访问器会为您处理内存管理(即在使用 self.varName = ...; 时),而 varName = ...; 只执行它所说的,即赋值 ->(这里有 EXC_BAD_ACCESS 错误的解释你可能会得到)。

从句法上讲,这两种形式都是正确的。如果你想更好地传达意图,当你想直接使用指针时使用self->varName,当你想利用@property的便利时使用self.varName

【讨论】:

  • 优秀的大纲。如果我们只做varName = ...;,您能否详细说明一下可能出现的问题
【解决方案3】:

以下是所有可能的组合(我认为) 只有当aString 属性具有retain 属性时,OK 和 BAD 才是正确的:

@property (nonatomic, retain) NSMutableString *aString;

所以:

1

aString = [[NSMutableString alloc] init]; //OK: 

这没关系,但仅在 aString 未指向无效对象的情况下,或者您将丢失对该对象的引用并且它会泄漏,因为您将无法到达它以释放它。

2

aString = [NSMutableString string]; //BAD

不好,因为您应该保留 aString(正如您声明的那样),您没有保留它,将来您肯定会得到 EXC_BAD_ACCESS

3

aString = [[NSMutableString string] retain]; //OK

与第一种方法相同,仅当 aString 未指向有效对象时才有效。不过我会使用第一个。

4

aString = [[[NSMutableString alloc] init] autorelease];//BAD

与第二种方法相同。

5

self.aString = [[NSMutableString alloc] init]; //BAD!!

不好,因为你要保留它两次,因此会导致内存泄漏

6

self.aString = [[NSMutableString string]; //******GOOD!******

这可能是最安全的。它将由属性设置器保留,并且由于您正在使用设置器,因此 aString 可能已指向的任何其他对象都将被适当地释放

7

self.aString = [[NSMutableString string] retain]; //BAD

这被保留了两次。

8

self.aString = [[[NSMutableString alloc] init] autorelease];//Ok

这也可以,但我会使用方便的方法而不是这种冗长的方法:)

如果您知道自己在做什么,请注意#1 和#3 选项非常好。事实上,我比#6 更频繁地使用它们

【讨论】:

  • 感谢您的解决方案!感谢您列出不同的组合,这很有帮助!我最常使用 #1,但我没有意识到 6 也可以。
【解决方案4】:

我个人更喜欢使用self. 语法。它只是更容易确定它是一个实例变量,而不仅仅是当前范围内的一些其他变量,当它的 NSAutoreleasePool 耗尽时,这些变量将丢失。但是,两种方式都使用它们是正确的,如果您收到 EXC_BAD_ACCESS 错误,这并不是因为您在没有使用self. 的情况下访问它。你说你必须分配它是正确的,无论你选择哪种方式访问​​你的变量,都要保持一致,否则你会收到错误。

我希望这会有所帮助。

【讨论】:

    【解决方案5】:

    始终使用访问器,initdealloc 和访问器本身除外。这样做会为您省去很多麻烦,就像您所描述的那样。此外,将您的 ivars 命名为与您的属性不同的名称(_foofoo_mFoo,但不是 foo)。

    self.foo[self foo] 完全相同。我调用方法fooself.foo = x[self setFoo:x] 完全相同。它调用方法setFoo:。如果您将属性foo 合成为retain 变量,则如下所示:

    @synthesize foo = foo_;
    
    - (void)setFoo:(id)value {
      [value retain];
      [foo_ release];
      foo_ = value;
    }
    

    这会正确释放foo_ 的旧值,分配一个新值并保留它。

    foo = x(假设foo 是一个ivar)不调用任何方法。没有。它只是将x 中的指针的值分配给foo 中的指针。如果foo 指向被保留的东西,它就会被泄露。如果您分配的新值未保留,您稍后会崩溃。

    解决这个问题的方法是尽可能使用访问器。

    【讨论】:

    • 非常感谢!很好的总结,很有道理。我的 Objective-C 书籍/资源对此并没有说太多,这就是为什么我有些困惑。再次感谢!
    【解决方案6】:

    要么。

    使用点语法(对某些人来说)更简洁,并且可以编译为等效的。即self.iVar[self iVar] 相同,self.iVar = aValue[self setIVar:aValue]; 相同

    【讨论】:

    • 这不是他要问的,他是在问它是否应该有self。
    • 我明白了。我听说如果您尝试执行 iVar = aValue,这是不正确的,因为它不会正确“设置”值。这是真的?我认为这是我遇到的一个问题,但我从来没有真正理解它。
    • hmm 没有翻译成[self getIvar] ?
    • 没有。 self.iVar 基本上是[self iVar]iVar = aValue 是直接分配。没有retaincopy 发生在直接分配中。
    • @bioffe。 KVC 要求var 的访问器是-var 来检索值,-setVar: 来设置值。带有get 的Cocoa 方法名称用于通过引用返回值。例如getComponents 来自NSColor
    【解决方案7】:

    self.aString[self aString] 的语法糖。合成一个属性只需创建-aString-setAString: 方法(取决于你选择的属性而不是小题大做)。

    现在的问题是是否使用. 表示法。我建议你不要使用它。 为什么?首先要知道 Objective-C 的目标只是对 C 的补充。这意味着每个有效的 C 代码也是有效的 Objective-C 代码。

    现在看看他们用点符号做了什么。最后一条语句不再成立。您不会区分访问 C 结构的字段和发送 Objective-C 方法。

    所以请不要使用点符号。更喜欢使用 [self ..]。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-01
      • 2021-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多