如何避免子类无意中重写超类私有方法

时间:2013-01-31 14:10:13

标签: objective-c objective-c-category class-extensions

我正在写一个库,可能会被不是我的人使用。

假设我写了一堂课:

InterestingClass.h

@interface InterestingClass: NSObject
- (id)initWithIdentifier:(NSString *)Identifier;
@end

InterestingClass.m

@interface InterestingClass()
- (void)interestingMethod;
@end

@implementation InterestingClass
- (id)initWithIdentifier:(NSString *)Identifier {
  self = [super init];
  if (self) {
    [self interestingMethod];
  }
  return self;
}

- (void)interestingMethod {
  //do some interesting stuff
}
@end

如果某人稍后使用该库并决定创建InterestingClass的子类,该怎么办?:

InterestingSubClass.h

@interface InterestingSubClass: InterestingClass
@end

InterestingSubClass.m

@interface InterestingSubClass()
- (void)interestingMethod;
@end

@implementation InterestingSubClass
- (void)interestingMethod {
  //do some equally interesting, but completely unrelated stuff
}
@end

未来的库用户可以从公共接口看到initWithIdentifier是超类的方法。如果他们覆盖这个方法,他们可能会(正确地)假设应该在子类实现中调用superclass方法。

但是,如果他们定义了一个方法(在子类私有接口中),该方法无意中与超类“私有”接口中的无关方法同名?如果没有他们读取超类私有接口,他们就不会知道它们不仅仅是创建一个新方法,而且还覆盖了超类中的某些东西。子类实现最终可能会被意外调用,并且在调用方法时超类期望完成的工作将无法完成。

我读过的所有SO问题似乎都表明这只是ObjC的工作方式,而且没有办法绕过它。是这种情况,还是我能做些什么来保护我的'私人'方法不被覆盖?

或者,有没有办法从我的超类中调用方法的范围,所以我可以确定将调用超类实现而不是子类实现?

2 个答案:

答案 0 :(得分:3)

AFAIK,你可以期待的最好的就是声明覆盖必须要求超级。您可以通过将超类中的方法定义为:

来实现
- (void)interestingMethod NS_REQUIRES_SUPER;

这将编译时标记任何不会调用超级的覆盖。

答案 1 :(得分:1)

对于框架代码,处理此问题的一种简单方法是为所有私有方法提供私有前缀。

您经常会在堆栈跟踪中注意到Apple框架通常以下栏_开始调用私有方法。

如果您确实提供了一个人们无法看到您的来源的外部使用框架,那么这只是一个真正的问题。

<强> NB
不要使用下划线前缀启动方法,因为此约定已被保留