何时应该明确使用@synthesize?
据我所知,自XCode 4.4 @synthesize
将自动生成属性访问器。 但是现在我已经阅读了关于NSUndoManager
的代码NSUndoManager
,并且在代码中注意到@synthesize
被明确地添加了。 喜欢:
@interface RootViewController () @property (nonatomic, strong) NSDateFormatter *dateFormatter; @property (nonatomic, strong) NSUndoManager *undoManager; @end @implementation RootViewController //Must explicitly synthesize this @synthesize undoManager;
我现在感到困惑…什么时候应该明确地添加@synthesize
到我的代码?
有很多答案,但也是一个很大的混乱。 我会尝试下一些命令(或增加混乱,我们会看到…)
-
让我们停止谈论Xcode。 Xcode是一个IDE 。 铛是一个编译器 。 我们讨论的这个特性被称为属性的自动合成 ,它是由clang支持的Objective-C语言扩展 ,它是Xcode使用的默认编译器。
为了说清楚,如果你在Xcode中切换到gcc,你将不会受益于这个特性(不pipe从Xcode版本开始)。同样,如果你使用文本编辑器并且使用命令行中的clang编译,将。 -
感谢自动合成,你不需要显式合成属性,因为它会被编译器自动合成
@synthesize propertyName = _propertyName
但是,有一些例外:
-
用自定义getter和setter来读写属性
当提供getter和setter自定义实现时,该属性将不会自动合成
-
只读属性与自定义getter
当为readonly属性提供自定义getter实现时,将不会自动合成
-
@dynamic
当使用
@dynamic propertyName
,属性不会自动合成(非常明显,因为@dynamic
和@synthesize
是互斥的) -
在@protocol中声明的属性
当符合协议时,协议定义的任何属性将不会自动合成
-
在类别中声明的属性
这是
@synthesize
指令不被编译器自动插入的情况,但是这个属性不能手动合成。 虽然类别可以声明属性,但是它们不能被合成,因为类别不能创buildivars。 为了完整起见,我将补充说, 使用Objective-C运行时仍然可以伪造属性综合 。 -
重写的属性 (新的铛-600.0.51,与Xcode 6一起发货,谢谢MarcSchlüpmann)
当你重载一个超类的属性时,你必须明确地合成它
-
值得注意的是,合成一个属性会自动合成支持ivar,所以如果属性合成丢失,除非明确声明,否则ivar也将丢失。
除了最后三种情况之外,一般的理念是,只要手动指定一个属性的所有信息(通过实现所有访问器方法或者使用@dynamic
),编译器就会假定你想完全控制这个属性,并且会禁用它自动合成。
除了上面列出的情况之外,显式@synthesize
的唯一其他用途是指定一个不同的伊娃名称。 然而,约定是重要的,所以我的build议是始终使用默认的命名。
如果你没有明确地使用@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
链接到iVar
。 如果你想为它生成特定的getter和setter。 但是在给定的代码中没有iVar
,我认为这个@synthesize
是没用的。 但是现在我想新的问题是“什么时候使用iVar
?”,而我对这个问题没有任何其他的回应。
什么时候应该添加@synthesize
显式给我的代码?
一般来说,如果需要的话:你可能永远不会遇到需要的情况。
有一种情况你可能觉得它很有用。
假设你正在编写一个自定义的getter和setter,但是需要一个实例variables来支持它。 (对于一个atomic属性,这和想要一个自定义setter一样简单:如果你为monatomic属性指定一个setter,编译器将写入一个getter,但不是一个atomic属性。)
考虑一下:
@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(正确)不会为它创build一个支持实例variables。
你有两个select让它存在。 您可以将@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的时候,它可以用来定义属性支持的实例variables。 你可以决定在这里你想使用的forms。
在过去,我喜欢在@implementation {}
指定实例variables,但现在我认为@synthesize
路由是一个更好的select,因为它删除了冗余types,并明确地将支持variables@implementation {}
到属性:
- 更改属性的types,并更改实例variables的types。
- 更改其存储限定符(例如,使其弱而不是强或弱,而不是弱)和存储限定符更改。
- 删除或重命名该属性,@
@synthesize
将生成编译器错误。 你不会最终得到stream浪的实例variables。
* – 我知道一个有必要的情况,涉及在多个文件中跨类别分割function。 如果苹果修复这个问题,甚至已经有了,我也不会感到惊讶。
好的,当你创build一个属性…
@property NSString *name;
Xcode将自动合成一个iVar,就像你写了…
@synthesize name = _name;
这意味着你可以访问财产与…
self.name; // or _name;
要么工作,但只有self.name
实际上使用访问器方法。
自动合成只有一次不起作用。
如果你覆盖,但setter和getter方法,那么你将需要综合iVar。
如果你只是重写setter,或者你只是重写getter,你没问题。 但是如果两者都做,编译器就不会理解它,你需要手动合成它。
作为一个经验法则。
不要制造iVar。 只要使用该属性。 不要综合它。
在协议中声明财产时,需要进行财产综合。 它不会在实现界面中自动合成。
感谢澄清。 我有一个类似的问题。
@synthesize firstAsset, secondAsset, audioAsset; @synthesize activityView;
所以,现在,在评论他们的时候,我经历了每一次事件
self.firstAsset看来我也可以使用firstAsset,但我发现我很想看到“ ”太频繁。
Xcode不需要显式的@synthesize
声明。
如果你不写@synthesize
它一样做:
@synthesize manager = _manager;
示例代码可能已经过时了。 他们会尽快更新。
您可以访问您的属性,如:
[self.manager function];
这是苹果推荐的惯例。 我遵循它,我build议你也这样做!