我什么时候应该明确使用@synthesize?

时间:2013-11-05 08:19:04

标签: objective-c properties synthesize

据我所知,自XCode 4.4起,@synthesize将自动生成属性访问器。但是刚才我已经阅读了有关NSUndoManager的代码示例,并在代码中注意到@synthesize已明确添加。像:

@interface RootViewController  ()

@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property (nonatomic, strong) NSUndoManager *undoManager;

@end

@implementation RootViewController
//Must explicitly synthesize this
@synthesize undoManager;

我现在感到困惑......我什么时候应该明确地将@synthesize添加到我的代码中?

7 个答案:

答案 0 :(得分:152)

有很多答案,但也有很大的困惑。我会尝试下订单(或增加一些混乱,我们会看到......)

  1. 让我们停止谈论Xcode。 Xcode是 IDE 。 clang是编译器。我们讨论的这个特性叫做属性的自动合成,它是一个Objective-C language extension supported by clang,它是Xcode使用的默认编译器。
    为了说清楚,如果你在Xcode中切换到gcc,你将无法从这个功能中受益(无论是Xcode版本。)同样如果你使用文本编辑器并使用命令行中的clang编译,你将

  2. 感谢自动合成,您不需要显式合成属性,因为它将由编译器自动合成为

    @synthesize propertyName = _propertyName
    

    但是,存在一些例外情况:

    • 使用自定义getter和setter的readwrite属性

      当提供两者 getter和setter自定义实现时,该属性将不会自动合成

    • 使用自定义getter的readonly属性

      为readonly属性提供自定义getter实现时,不会自动合成

    • <强> @dynamic

      使用@dynamic propertyName时,该属性不会自动合成(非常明显,因为@dynamic@synthesize是互斥的)

    • 在@protocol

      中声明的属性

      当符合协议时,协议定义的任何属性都不会自动合成

    • 在类别中声明的属性

      这种情况下编译器不会自动插入@synthesize指令,但也无法手动合成此属性。虽然类别可以声明属性,但它们根本无法合成,因为类别无法创建ivars。为了完整起见,我将补充一点,它仍然可以to fake the property synthesis using the Objective-C runtime

    • 已覆盖的属性(自clang-600.0.51以来的新版本,随Xcode 6发布,感谢MarcSchlüpmann)

      当覆盖超类的属性时,必须明确地合成它

  3. 值得注意的是,合成属性会自动合成背景ivar,因此如果缺少属性合成,除非明确声明,否则ivar也会丢失。

    除了最后三种情况,一般的理念是,无论何时手动指定有关属性的所有信息(通过实现所有访问器方法或使用@dynamic),编译器都会假定您希望完全控制属性,它将禁用它上面的自动合成。

    除了上面列出的情况之外,显式@synthesize的唯一其他用途是指定不同的ivar名称。但是约定很重要,所以我的建议是始终使用默认命名。

答案 1 :(得分:17)

如果您没有明确使用@synthesize,编译器会以相同的方式理解您的属性

@synthesize undoManager=_undoManager;

然后您就可以在代码中写下以下内容:

[_undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter

这是常见的惯例。

如果你写

@synthesize undoManager;

你将拥有:

[undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter

我个人不再使用@synthesize,因为它不再是强制性的。 对我而言,使用@synthesize的唯一原因是将iVar@property相关联。如果你想为它生成特定的getter和setter。 但是在给定的代码段中没有iVar,我认为这个@synthesize是没用的。但是现在我认为新的问题是“何时使用iVar?”,而我对此没有其他回应而不是“永远”!

答案 2 :(得分:11)

我应该何时将@synthesize明确添加到我的代码中?

一般情况下,如果需要:您可能永远不会遇到需要的情况。

但是有一种情况你可能会发现它很有用。

假设您正在编写自定义getter和setter,但需要一个实例变量来支持它。 (对于原子属性,这就像想要自定义setter一样简单:如果为单原子属性指定了setter而不是原子属性,编译器将编写一个getter。)

考虑一下:

@interface MyObject:NSObject
@property (copy) NSString *title;
@end

@implementation MyObject

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

这不起作用,因为_title不存在。您已经指定了getter或setter,因此Xcode(正确)不会为它创建支持实例变量。

enter image description here

让它存在有两种选择。您可以将@implementation更改为此:

@implementation MyObject {
    NSString *_title;
}

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

或者将其更改为:

@implementation MyObject

@synthesize title = _title;

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

换句话说,虽然合成是出于实用目的而不必要*,但是当您提供getter / setter时,它可以用于定义属性支持实例变量。您可以决定要使用哪种表格。

过去,我倾向于在@implementation {}中指定实例变量,但我现在认为@synthesize路由是更好的选择,因为它删除了冗余类型并明确地绑定了支持变量到酒店:

  1. 更改属性的类型,并更改实例变量的类型。
  2. 更改其存储限定符(例如,使其变弱而不是强或强而不是弱)并且存储限定符会更改。
  3. 删除或重命名该属性,@synthesize将生成编译器错误。您不会最终得到杂散的实例变量。
  4. * - 我知道有必要的一个案例,涉及跨多个文件中的类别拆分功能。如果Apple修复此问题,甚至已经修复过,我也不会感到惊讶。

答案 3 :(得分:6)

好的,当你创建一个属性......

@property NSString *name;

Xcode将自动合成iVar,就像你写的那样......

@synthesize name = _name;

这意味着您可以使用...

访问该媒体资源
self.name;
// or
_name;

要么可以工作,但只有self.name实际使用访问者方法。

只有一次自动合成不起作用:如果你覆盖了setter和getter方法,那么你将需要合成iVar。

如果你只是覆盖了setter,或者只是覆盖了getter,那你就没问题了。但如果您同时执行这两项操作,则编译器将无法理解它,您需要手动合成它。

虽然是经验法则。

不要制作iVars。 只需使用该物业。 不要合成它。

答案 4 :(得分:1)

在协议中声明属性时,需要属性合成。它不会在实现界面中自动合成。

答案 5 :(得分:0)

感谢您澄清。我有类似的问题。

@synthesize firstAsset, secondAsset, audioAsset;
@synthesize activityView;

所以现在,在对它们进行评论后,我经历了并用例如

替换了每一个事件

self.firstAsset似乎我也可以使用 firstAsset,但我发现我错过了&#34; &#34;太频繁。

答案 6 :(得分:-1)

Xcode不需要明确的@synthesize声明。

如果你不写@synthesize,那就像在做:

@synthesize manager = _manager;

示例代码可能已经过时了。他们很快就会更新。

您可以访问以下属性:

[self.manager function];

这是Apple的推荐惯例。我遵循它,我建议你也这样做!