如何避免子类无意中覆盖超类的私有方法

6

我正在编写一个库,可能会被其他人使用。

假设我写了一个类:

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
不,我认为你无法对此做任何事情:https://dev59.com/_mct5IYBdhLWcg3wgNcy - trojanfoe
2个回答

3
据我所知,您能期望的最好情况是声明覆盖必须调用 super。您可以通过在超类中定义方法来实现这一点,如下所示:
- (void)interestingMethod NS_REQUIRES_SUPER;

这将在编译时标记任何未调用super的覆盖。

这是一个相当可行的(而且可能看起来更干净)替代方案,可以在所有方法名称之前添加某种唯一字符串。干杯! - sam-w
根据这个讨论,可以通过以下方式消除clang警告:#pragma clang diagnostic push \ #pragma clang diagnostic ignored "-Wobjc-missing-super-calls" \ <插入方法名称> \ #pragma clang diagnostic pop - sam-w
@Clay,这对我没有解决。这只是添加了一个警告! - orafaelreis

1

对于框架代码,处理这个问题的简单方法是给所有私有方法添加一个私有前缀。

你经常会在堆栈跟踪中注意到,苹果框架经常调用以下划线_开头的私有方法。

只有当您确实提供外部使用的框架时,人们无法查看您的源代码,这才会真正成为一个问题。

NB
不要以下划线前缀开头的方式开始您的方法,因为此约定已经被保留。


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