在objective-c中@property和@synthesize

sar*_*unw 18 synthesis properties objective-c

当我在https://github.com/enormego/EGOTableViewPullRefresh玩游戏并弄清楚它是如何工作的时候,我发现了@property和@synthesize的神秘感.这是我提到的代码

EGORefreshTableHeaderView.h

@interface EGORefreshTableHeaderView : UIView {
    id _delegate;
    EGOPullRefreshState _state;

    UILabel *_lastUpdatedLabel;
    UILabel *_statusLabel;
    CALayer *_arrowImage;
    UIActivityIndicatorView *_activityView;
}

@property(nonatomic,assign) id <EGORefreshTableHeaderDelegate> delegate;
Run Code Online (Sandbox Code Playgroud)

EGORefreshTableHeaderView.m

@synthesize delegate=_delegate;
Run Code Online (Sandbox Code Playgroud)

我已经阅读了这个http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html,据我所知,它为_delegate创建了一个新的名称,即委托.(这是我的理解吗?)

但我仍然不明白为什么他们必须使那些@synthesize =指令复杂化.

Cal*_*leb 30

这有多复杂,真的吗?这只是一些语法,允许您指定要用于支持您告诉编译器创建访问器的属性的ivar.如果他们没有提供这个或类似的东西,那么你总是必须让你的属性名称与你的ivar名称相匹配,并且有理由你可能不希望这样.

如果您不需要以不同方式命名您的ivars,那么您不必费心指定ivar名称.实际上,您根本不必为您的属性创建ivars ...如果不这样做,编译器将为您创建它们.

更新:截至2013年中期,LLVM默认为合成属性的访问器,因此在大多数情况下,您根本不需要再指定@synthesize.您仍然可以使用它的一种情况是,您希望使用与编译器为您生成的实例变量不同的实例变量来备份该属性.此外,支持属性的ivar的默认名称将是前缀为下划线的属性名称.因此,可以通过删除行来简化OP示例中的代码:

id _delegate;
Run Code Online (Sandbox Code Playgroud)

和:

@synthesize delegate=_delegate;
Run Code Online (Sandbox Code Playgroud)

我已经删除了我之前关于使用下划线前缀的建议,因为它明显不同意编译器的当前时尚和默认行为.据我所知,为方法名称使用下划线前缀仍然是不好的形式.

此外,我注意到至少有一个人解释了我的回答的第一行,"它有多复杂,真的吗?" 居高临下.我希望这只是一个人的印象 - 我绝对不打算任何屈尊俯就,而只是试图围绕OP的断言表明我的回应,即该@synthesize xxx=_xxx;指令使事情变得复杂.当你开始时,有很多东西要吸收; 希望新的"默认合成"行为将减轻新人的负担.

  • @art使用`@synthesize delegate = _delegate`,只有一个名为`_delegate`的实例变量和两个名为`-delegate`和`-setDelegate:`的访问器方法.如果它是`@synthesize delegate`,则会有两个实例变量,`_delegate`和`delegate`,以及两个名为`-delegate`和`-setDelegate:`的访问器方法. (9认同)
  • 我是obj-c的新手,这不是我提到的代码,所以这对我来说很复杂.那么这里发生的事情只是引用同一个obj的两个名字吧?@synthesis newName = ivar不会创建新的另一个ivar,但引用了旧的ivar吧? (6认同)
  • 由于我是将第一行解释为居高临下的人,我想我不妨评论一下.我花了很长时间才弄清楚为什么@synthesize没有按照我的预期行事,这是谷歌搜索的第一个搜索结果之一.在与指令挣扎了一段时间之后,阅读"它有多复杂?" 确实听起来居高临下,但我很欣赏后续行动.谢谢你的详细解答. (5认同)

War*_*ton 17

你是对的,使用

@synthesize foobar=_foobar;

在大多数情况下,它有点无意义,但在抽象级别,它确实允许您完全返回其他变量的值.如...

@synthesize foobar=fluffybunny;

允许您获取或设置fluffybunny每次使用访问者时的值.foobar

但是就@synthesize复杂性而言,您更愿意写作

-(void)setFoobar:(id)aobject {
    [self willSetValueForKey:"foobar"];
    id old = foobar;
    foobar = [aobject retain];
    [old release];
    [self didSetValueForKey:"foobar"];
}

-(id)foobar {
    [self willAccessValueForKey:"foobar"];
    id obj = [self primitiveValueForKey:@"foobar"];
    [self didAccessValueForKey:"foobar"];    
    return obj;
}
Run Code Online (Sandbox Code Playgroud)

要么

@synthesize foobar;
Run Code Online (Sandbox Code Playgroud)

这不是特别好写,因为我忘记了如何做得好,但@synthesize指令阻止你必须多次写入访问器.它是关于Obj-C 1.0的重要事情之一.

免费代码,不要敲它.

  • Xcode 4.4.1 forward中的最新编译器意味着您甚至不必再使用合成xyz.当你声明@property xyz时,你得到一个隐含的声明,让你免费合成xyz = _xyz. (7认同)
  • @WarrenBurton是正确的,但是如果你自定义实现`xyz`的getter和setter那么你仍然必须使用`@synthasize xyz = _xyz` (2认同)