【问题标题】:When should I use @synthesize explicitly?我什么时候应该明确使用@synthesize?
【发布时间】:2013-11-16 01:25:23
【问题描述】:

据我所知,从 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 明确添加到我的代码中?

【问题讨论】:

  • 示例代码可能是旧的。基本上,除非它变成一个问题,否则使用它(例如,委托中的属性不会自动合成)
  • 尝试注释掉@sythesize。如果代码仍然有效,则没有必要。

标签: objective-c properties synthesize


【解决方案1】:

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

@property NSString *name;

Xcode 会自动合成一个 iVar,就像你写的一样......

@synthesize name = _name;

这意味着您可以使用...访问该属性

self.name;
// or
_name;

两者都可以,但只有 self.name 实际使用访问器方法。

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

如果你只是覆盖 setter 或者你只是覆盖 getter,你就可以了。但如果两者都做,那么编译器将无法理解它,您需要手动合成它。

不过根据经验。

不要制作 iVar。 只需使用该属性。 不要合成它。

【讨论】:

  • 自动合成不执行的情况更多。看看我的回答。
  • @GabrielePetronella 你能为普通读者简明扼要地列出这些案例吗?
  • @DanRosenstark 这与现在编程的任何人都无关。你真的应该使用 Swift。 TBH 我认为整个合成的东西甚至不再是 ObjC 的东西了。除非您正在使用 5 年以上的代码库。
  • @Fogmeister 是的,在您在回答中提到的情况下(您同时覆盖 setter 和 getter),这仍然是一件事。至于Objective-C“与现在的任何编程人员无关”,请打电话给我的日常工作并告诉他们。还要告诉 Facebook、Google 和 Apple,它们在内部使用 Objective-C 效果很好。
  • 如果没有 Quora,我敢肯定这是真的,但无论如何:quora.com/…
【解决方案2】:

有很多答案,但也有很大的困惑。我会试着整理一些东西(或者增加混乱,我们会看到......)

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

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

    @synthesize propertyName = _propertyName
    

    但是,也有一些例外:

    • 具有自定义 getter 和 setter 的读写属性

      同时提供 getter 和 setter 自定义实现时,不会自动合成属性

    • 带有自定义 getter 的只读属性

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

    • @动态

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

    • @protocol 中声明的属性

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

    • 在类别中声明的属性

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

    • 覆盖属性(自 clang-600.0.51 以来的新特性,随 Xcode 6 一起提供,感谢 Marc Schlüpmann)

      当您覆盖超类的属性时,您必须显式合成它

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

除了最后三种情况外,一般原则是,每当您手动指定有关属性的所有信息(通过实现所有访问器方法或使用@dynamic)时,编译器都会假定您希望完全控制该属性并且它会禁用它的自动合成。

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

【讨论】:

  • 如果原来的提问者还在,我认为这个答案应该被接受。这是最完整的。
  • 据我记得,在类别中指定的属性也不会自动合成。 (根本原因是您不能在类别中添加实例变量。)
  • @MartinR,说得好。它们不是自动合成的,但它们也不能手动合成,因为在一个类别中 @synthesize 是被禁止的(类别中没有 ivar,正如您已经指出的那样)。我会添加注释。
  • 但是这个答案没有解决具体问题:什么时候应该使用@synthesize?总是,从不,只有在满足某些条件时?
【解决方案3】:

如果您没有显式使用@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?”,而对于这个问题,我除了“从不”之外没有其他回应!

【讨论】:

  • 同意,我停止使用@synthesize,因为没有理由再这样做了。此外,前导下划线作为一个很好的视觉标志,让您知道您正在解决属性提供的内存管理和线程安全网(您应该在 initdealloc 方法中跳过它们)。
  • 问题是,什么时候需要明确需要合成。你根本没有回答。
  • 我今天发现这不是完全正确的。如果没有@synthesize,您将负责创建支持实例变量。有了它,编译器就会为你做这件事。
  • 我没有对任何人投反对票。 :)
  • -1 您完全错过了需要显式合成的情况。这也是一个编译器特性,而不是 Xcode 特性。
【解决方案4】:

感谢您澄清这一点。我遇到了类似的问题。

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

所以现在,在将它们注释掉后,我将每个出现的地方都替换为例如

self.firstAsset 看来我也可以使用 firstAsset,但我发现我经常错过看到“”。

【讨论】:

    【解决方案5】:

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

    如果你不写@synthesize 和写一样:

    @synthesize manager = _manager;
    

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

    您可以访问您的属性,例如:

    [self.manager function];
    

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

    【讨论】:

    • 声明 [_manager function] 不会访问该属性,而是会直接访问底层 ivar。
    • @CouchDeveloper 如果你要吹毛求疵,你应该准确。该属性由几件事组成,包括 ivar。所以最好说[_manager function]使用属性的访问器
    • @CouchDeveloper - 谢谢!修复! :)
    • @NikolaiRuhe 你是对的 Nikolai,我应该更准确。 ;)
    【解决方案6】:

    我应该何时将@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(正确地)不会为其创建支持实例变量。

    你有两个选择让它存在。您可以将@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
    

    换句话说,尽管 synthesize 出于实际目的从来没有必要*,但当您提供 getter/setter 时,它可用于定义属性支持实例变量。您可以在此处决定要使用哪种表格。

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

    1. 改变属性的类型,实例变量的类型也会改变。
    2. 更改其存储限定符(例如,将其设为弱而不是强或强而不是弱)并且存储限定符会更改。
    3. 删除或重命名该属性,@synthesize 将生成编译器错误。您不会得到杂散的实例变量。

    *-我知道有一种情况是必要的,涉及在多个文件中跨类别拆分功能。如果 Apple 解决了这个问题,甚至已经解决了,我也不会感到惊讶。

    【讨论】:

    • 你确定吗?你有没有试过?我写了许多自定义设置器和获取器,但从未合成过我的属性。 (我用了你的第一个例子,你说它不起作用)
    • 是的,我确定。代码是从新项目中复制粘贴的。它不适用于最新版本的 Xcode除非您在属性上指定非原子。
    • 是的,这是真的.. 但 99% 的时间你的属性都是非原子的。因此,只有在极少数情况下,您的属性是原子的,并且您需要一个您实际需要合成的自定义 getter/setter。
    • 如果您为 both setter 和 getter 提供自定义实现,那么编译器将假定您正在控制该属性并且不会为您合成它。
    • 我同意你的观点,尽管我可以理解为什么 Apple 最初认为这是一个好主意。真正的痛苦是atomic 直到后来才被添加为属性说明符。现在它已经出现了,您可能会发现警告标志 CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES 很有趣。
    【解决方案7】:

    在协议中声明属性时需要进行属性综合。它不会在实现接口中自动合成。

    【讨论】:

    • 是的,但这只是一种情况。您可能需要详细说明。
    • @GabrielePetronella 这是我在这么晚的时候唯一能想到的。 =]
    猜你喜欢
    • 2010-11-02
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 2020-12-22
    • 2021-09-07
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多