【问题标题】:Objective-C synthesize property name overridingObjective-C 综合属性名称覆盖
【发布时间】:2010-09-27 10:16:05
【问题描述】:

我正在尝试理解 synthesize 指令的用途,其中包含属性名称覆盖。假设我有一个定义如下的接口:

@interface Dummy ... {
    UILabel *_dummyLabel;
}

@property (retain, nonatomic) UILabel *dummyLabel;

在实现文件中,我有:

@synthesize dummyLabel = _dummyLabel;

据我了解,“dummyLabel”只是实例变量“_dummyLabel”的别名。 self._dummyLabel 和 self.dummyLabel 有区别吗?

【问题讨论】:

    标签: objective-c synthesizer


    【解决方案1】:

    是的。 self._dummyLabel 未定义,但 _dummyLabel 未定义。

    点语法扩展到简单的方法调用,因此它并不特定于属性。如果你有一个名为-(id)someObject 的方法,例如object.someObject 的情况,就好像你写了[object someObject];

    self.dummyLabel  //works
    self._dummyLabel //does not work
    dummyLabel       //does not work
    _dummyLabel      //works
    [self dummyLabel];  //works
    [self _dummyLabel]; //does not work
    

    【讨论】:

    • 感谢您的快速回答。嗯...好吧,[self.dummyLabel setText:@"..."] 和 [_dummyLabel setText:@"..."] 做同样的事情吗?如果是这样,我认为将 _dummyLabel 重命名为 dummyLabel 没有什么大的优势。
    • ivar 使用另一个名称而不是属性名称的好处是,当您访问其中一个或另一个时,您可以在代码中轻松看到。
    • 所以 self.dummyLabel 的意思是 this.getDummyLabel() ,如果我想用 java 术语来说,_dummyLabel 的意思就是 this.dummyLabel?
    【解决方案2】:

    你的理解不正确。 dummyLabel 是属性的名称,并且不是实例变量的别名 - 实例变量称为_dummyLabel。因此,对于名为myObjectDummy 实例,以下内容成立:

    • [myObject dummyLabel] 工作
    • myObject.dummyLabel 工作
    • [myObject _dummyLabel] 失败
    • myObject._dummyLabel 失败
    • myObject->dummyLabel 失败
    • myObject->_dummyLabel 取决于 ivar 的可见性(@public@private@protected
    • [myObject valueForKey: @"dummyLabel"] 工作
    • [myObject valueForKey: @"_dummyLabel"] 取决于 +accessInstanceVariablesDirectly 的实现(即,它将在 +accessInstanceVariablesDirectly 返回 YES 的默认情况下工作)。

    【讨论】:

    • 那么,当我想在一个方法中访问一个实例变量时,我可以使用_dummyLabel = @"blah"——这会直接改变值,而不是通过一个setter?所以我可以有一个没有设置器的只读属性,但仍然可以通过直接进入 ivar 在内部进行更改?如果我想在类的方法中使用getter/setter,我只需使用self.dummyLabel?或者我也可以直接使用dummyLabel
    【解决方案3】:

    拥有另一个名字的好处 对于 ivar 比对于属性是 您可以在代码中轻松看到 当您访问一个或 其他 - 安德烈 K

    我找不到“评论”按钮,所以我不得不发布为“答案”。

    只是想扩展 Andre 的评论 - 通过了解您何时使用合成属性与普通变量,您知道(尤其是在设置器的情况下)何时自动保留/复制/释放变量,这要归功于您的好设置器, 与手动操作。

    当然,如果你做对了,你可能不需要 setter 的帮助来正确地保留/释放对象!但是在其他情况下,将您的 ivars 称为 self.ivar 而不是 _ivar 可能会有所帮助,例如当您使用自定义 setter/getter 而不是默认合成的时。也许每次你修改一个属性时,你也想把它存储到 NSUserDefaults 中。所以你可能有一些这样的代码:

    @interface SOUserSettings : NSObject {
    
    BOOL _autoLoginOn;
    
    }
    
    @property (nonatomic, assign) BOOL autoLoginOn;
    
    @end
    
    @implementation SOUserSettings
    
    @synthesize autoLoginOn = _autoLoginOn;
    
    - (void)setAutoLoginOn:(BOOL)newAutoLoginOnValue {
    
       _autoLoginOn = newAutoLoginOnValue;
       [[NSUserDefaults standardUserDefaults] setBool:_autoLoginOn forKey:@"UserPrefAutoLoginOn"];
    }
    
    @end
    

    注意:这只是说明性代码,它可能有一千个错误!

    所以现在,在你的代码中,如果你有一行写着 _autoLoginOn = YES - 你知道它不会被保存到 NSUserDefaults,而如果你使用 self.autoLoginOn = YES 你就知道会发生什么。

    _autoLoginOnself.autoLoginOn 之间的区别不仅仅是语义上的。

    【讨论】:

    • 太好了,你提到了!确实有区别!
    【解决方案4】:

    我看不出有什么大的优势 将 _dummyLabel 重命名为 dummyLabel

    在某些 ObjC 运行时中,您很难使实例变量对类的用户不可见。对于他们来说,在您的实例变量上加上一些前缀(或后缀)可以清楚(或更清楚)您不希望任何人弄乱您的变量。但是,您不希望在您的公共职能上出现这种情况。这可以让你摆脱它。

    如果您需要同时维护具有一组名称的旧接口以及具有一组新名称的新 API 集(setLastname 与 setSurname),它也很有用。

    【讨论】:

      【解决方案5】:

      旧帖子,但我认为值得一提的是,建议通过 getter 和 setter 访问变量(因此,使用点表示法)。强烈建议仅在初始化时直接访问字段 (_ivar)。

      有一些很好的苹果文章: https://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html

      最后一段:

      您应该始终直接从内部访问实例变量 初始化方法,因为在设置属性时, 对象的其余部分可能尚未完全初始化。即使你 不要提供自定义访问器方法或知道任何副作用 在你自己的类中,未来的子类很可能会覆盖 行为。

      【讨论】:

        猜你喜欢
        • 2012-06-23
        • 1970-01-01
        • 1970-01-01
        • 2010-09-27
        • 2012-09-23
        • 1970-01-01
        • 1970-01-01
        • 2017-08-29
        • 1970-01-01
        相关资源
        最近更新 更多