【问题标题】:Why do I need to write @synthesize when I provide getter and setter?为什么我在提供 getter 和 setter 时需要写 @synthesize?
【发布时间】:2025-04-30 15:25:01
【问题描述】:

所以属性的自动合成很棒。但是,当您同时提供 getter 和 setter 时,会出现错误。

@property (strong, nonatomic) NSArray *testArray;

- (NSArray *)testArray {
    return _testArray;
}

- (void)setTestArray:(NSArray *)testArray {
    _testArray = testArray;
}

错误:Use of undeclared identifier '_testArray'

添加@synthesize testArray = _testArray; 解决了这个问题。我只是想知道这是为什么?

【问题讨论】:

  • 似乎您没有声明 ivar 本身。顺便说一句,这与 Xcode 完全无关。如果您使用 Eclipse 或 nano 并 make 编写程序,这不会有什么不同。
  • @property 在那里(问题是关于自动合成的属性)。此外,当您仅实现 getter 或 setter 时,它工作正常,只有当您同时执行时才会失败。
  • @property 正在声明 iVar

标签: objective-c properties synthesize


【解决方案1】:

当您同时提供 getter 和 setter 时,通常根本不需要实例变量,即当您只是转发这些消息或将数据存储在其他地方时。

一旦缺少其中一个,就需要 ivar 来合成该功能。

如果我没记错的话,对于只读属性,类比假设也成立。

【讨论】:

  • 就我而言,我确实需要后备存储,因为我需要在 getter 中进行一些初始化,并在 setter 中更新 UI。所以我猜@synthesize 行是要走的路?太糟糕了,我喜欢没有它们的文件是多么干净:)
  • 是的,在这种情况下它们是需要的 - 或者你可以在你的声明列表中放置一个 ivar,甚至在你的 .m 文件中。
【解决方案2】:

在最新的编译器/运行时下,当你使用时

@synthesize testArray = _testArray;

编译器创建

  • _testArray ivar,如果它不存在;
  • testArray 方法,如果你还没有实现它;
  • setTestArray: 方法,如果你还没有实现它。

如果你使用

@synthesize testArray;

如果testArray ivar 不存在,编译器会创建它,而不是_testArray

如果你不使用@synthesize,并且依赖自动合成,那么_testArray ivar 仅在(两者都必须申请)时创建

  • _testArray 尚不存在;
  • 已合成至少一种方法(readonly 的 getter,readwrite 的 getter 和/或 setter)。

在您的示例中,您已经实现了所有方法,因此自动合成不会合成任何方法,因此它不会创建 ivar。您可以自己声明_testArray ivar,也可以像以前一样使用显式综合。

【讨论】:

  • 感谢您的详细解答。
  • 在您回答的第二部分中,我不确定您是否需要有一个 getter/setter 才能生成 iVar。我有很多@property,它们没有任何明确的getter/setter,没有明确的@synthesize,我可以通过[self myProperty] 或_myProperty 很好地访问它们。现代运行时消除了这种样板代码。
  • 这就是我要说的。如果你有一个 @property,没有显式的 @synthesize,并且没有实现 getter/setter,那么 getter/setter 将被自动合成,因此将创建一个 _propertyname ivar。
  • 我有一个问题,在您的示例中,testArray 不是已经通过指定 (at)property *testArray 声明的吗?是让我感到困惑的事情之一,在我的情况下,我当然不需要 (at)synthesize 因为我创建了自己的 setter 和 getter 方法并且已经声明了 (at) 属性,如果我没有 (at)synthesize我得到一个错误。这是迄今为止我读过的最好的答案,(at)Synthesize 和 (at)Property 非常抽象。
【解决方案3】:

我做了一些测试:

根据最近的 Objective-c 约定,您不需要合成属性。

如果你这样做了

@property (strong, nonatomic) Business* theBiz;

iOs 会自动创建一个名为 _theBiz 的私有 ivar 变量;

如果你只实现一个 getter 或一个 setter,它似乎工作得很好:

-(void)setTheBiz:(Business *)theBiz
{
    _theBiz = theBiz;
}

但是,如果你声明 BOTH,即使其中一个只是空函数,你也会得到编译错误。

-(void)setTheBiz:(Business *)theBiz
{
    _theBiz = theBiz;
}

-(Business *) theBiz
{

}

当你同时实现 getter 和 setter 时,你会得到一个编译错误,说没有 _theBiz 这样的东西。

这可以很容易地通过添加:

@synthesize theBiz = _theBiz;

但这与 Objective-c 的这一令人敬畏的新功能的全部意义相悖。

我想知道这是设计使然,还是我只是遗漏了一些东西。苹果是什么东西?

我最好的猜测是这是一个错误。

纪尧姆的回答没有解决这个事实。

他说

至少已经合成了一种方法

如果设置了一个 getter 或 setter,似乎就会创建 _theBiz。当 both 被设置时,它不再被创建,这一定是一个错误。事实上,根本不需要设置任何变量,仍然会创建 ivar。

解决这个问题的唯一方法是明确地做

@synthesize theBiz = _theBiz;

【讨论】:

  • Guillaume 的回答确实解决了这个事实:“在您的示例中,您已经实现了所有方法,因此自动合成不会合成任何方法,因此它不会创建 ivar。您可以声明 _testArray ivar 你自己,或者像你一样使用明确的综合。”另外,您的回答基本上正是我的问题:)
  • Guillaume 这样说:“至少已经合成了一种方法(getter for readonly,getter and/or setter for readwrite)。”那是错误的。如果 BOTH 方法得到了合成,则不会创建 ivar。如果您同时实现了这两种方法,也没有理由不创建 ivar。
  • 如果你不喜欢这个答案,我应该删除它。我仍然认为这是一个错误。