Objective-C:使用实例变量(使用_)覆盖getter和setter

9

我是一名正在学习Swift编程语言的初学者,在此过程中,有时会接触到旧的Objective-C编程语言及其代码。

我想更好地理解Setter和Getter,因此有些问题需要请教。

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

例如:

Vehicle .h 文件:

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

因为我创建了这个属性,在vehicle.m文件中不需要声明Getter和Setter方法,因为它们会被编译器自动创建。所以我可以创建一个vehicle对象,设置并获取值。 示例 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)。这样做对吗?
我尝试了这个方法,但总是出现错误,不知道原因和要点。
示例:
Vehicle.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。

我不确定为什么会卡住,也不知道关键点在哪里。您能解释一下吗? 提前感谢!

1个回答

10
如果你实现了所有的访问器方法,编译器将不再自动为你合成 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

And

@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,但正如我之前所说,在大多数情况下不需要这样做。再次感谢! - Salvatore
你可能需要getter和setter来放置调试断点或进行日志记录。 - Xys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接