【问题标题】:Objective-C: Overriding Getter & Setter with Instance Variable (using _) [duplicate]Objective-C:使用实例变量覆盖 Getter 和 Setter(使用 _)[重复]
【发布时间】:2017-07-15 15:10:14
【问题描述】:

我正在学习 Swift 编程语言,在此期间,我有时会接触到旧的 Objective-C 编程语言及其代码。

我是一个绝对的初学者,因此我有一些问题可以更好地理解 Setter 和 Getter。

所以,我知道我可以通过 .h 文件中的花括号创建实例变量,但通常我使用属性。这些属性由实例变量支持,并自动提供 Getter 和 Setter 方法。

示例:

车辆.h文件:

@interface Vehicle : NSObject 
@property int myProperty;
@end

因为我创建了这个属性,所以我不必在 vehicle.m 文件中声明 Getter 和 Setter 方法,因为它们是由编译器自动创建的。所以我可以创建一个车辆对象,设置并获取值。

示例

main.m

Vehicle *myvehicle = [[vehicle alloc] init];
[myvehicle myProperty] // myvehicle.myProperty
[myvehicle setMyProperty : 10] // myvehicle.myProperty = 10;

现在我读到可以覆盖我创建的属性“myProperty”的自动创建的 Getter 和 Setter 方法。在声明我自己的 Getter 和 Setter 版本时,我必须在 vehicle.h 和 vehicle.m 文件中声明两个方法。在vehicle.m 文件中,我不使用self 关键字调用对象,而是使用它自动创建的实例变量(_myProperty)。对吗?

我试过了,但总是出错,我不知道为什么,有什么意义。

示例

车辆.h文件:

@interface Vehicle : NSObject 
@property int myProperty;
-(int) myProperty; //my new Getter method
-(void) setMyProperty: (int)updatedMyProperty; //My new Setter method
@end

车辆.m文件:

    @implementation Vehicle

    -(int) myProperty {
      if (! _myProperty) {
        _myProperty = NO;
    }
      return _myProperty;
    }

   -(void) setMyProperty: (int)updatedMyProperty {
    if (_myProperty == updatedMyProperty) return;
    _myProperty = updatedMyProperty;
    }
    @end

我总是收到错误“使用未声明的标识符”,我不知道为什么。如果我理解正确,我不必使用 @synthesize 声明 ivar 或其名称,因为编译器会自动为我创建名为 _myProperty 的 ivar。当我想更改 ivar 的名称时,我只需要使用 @synthesize。

我不知道我为什么会卡住,问题是什么。你能解释一下吗? 提前致谢!

【问题讨论】:

    标签: objective-c oop overriding getter-setter


    【解决方案1】:

    如果您实现所有访问器方法,编译器将不再为您自动合成 ivar。在这种情况下,您必须自己明确地这样做。例如

    @synthesize myProperty = _myProperty;
    

    仅当您手动实现所有访问器方法时才需要这样做。原因是编译器足够聪明,知道如果你接管了访问器方法,你很可能不需要 ivar,也就是说,你可能正在做一些完全不同的事情,例如计算来自其他属性的值,设置/获取来自不同存储的值等。您可能希望编译器合成 ivar(在这种情况下,您添加上面的 @synthesize 语句),但同样可能您已经实现访问器方法,因为不需要支持 ivar(在这种情况下,您可以省略上面的 @synthesize 语句)。

    无论如何,继续使用您的简单示例,您会得到以下内容:

    @interface Vehicle : NSObject 
    @property (nonatomic) int myProperty;  // if you don't write atomic accessor methods, you really should be explicit that this is nonatomic
    
    // as an aside, even if you implement accessor methods, you don't have to declare them here
    //
    // -(int) myProperty; //my new Getter method
    // -(void) setMyProperty: (int)updatedMyProperty; //My new Setter method
    
    @end
    

    还有

    @implementation Vehicle
    
    // since you implemented all of the accessor properties, you have to manually synthesize the ivar
    
    @synthesize myProperty = _myProperty;
    
    - (int) myProperty {
        // do whatever you want here; note, the following doesn't make sense
        //
        // if (! _myProperty) {
        //     _myProperty = NO;
        // }
    
        return _myProperty;
    }
    
    - (void)setMyProperty:(int)updatedMyProperty {
        if (_myProperty == updatedMyProperty) return;
        _myProperty = updatedMyProperty;
    }
    @end
    

    显然,在上面的示例中编写这些特定的访问器方法是没有意义的,因为您没有提供任何新功能,所以您不会。您只需利用自动合成的访问器方法即可。

    但是在那些你真的需要编写自己的访问器方法的情况下,你必须明确地告诉编译器你是否也需要它来为你合成 ivar。

    【讨论】:

    • 感谢 Rob 的帮助和回答!这确实帮助我理解了幕后发生的原因和情况。在我使用的书中没有声明我必须在覆盖 getter 和 setter 时手动合成我的 ivar。所以,总结一下:在大多数情况下,我不需要合成任何东西。如果我想重写一个 getter 或 setter,因为我想实现更多代码,我不需要做任何事情只是重写。如果我想覆盖两者,我必须手动合成 ivar,但正如我之前所说,在大多数情况下,没有必要这样做。再次感谢!
    • 您可能需要 getter 和 setter 来放置调试断点或进行日志记录
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多