如何防止方法被错误地覆盖?

时间:2022-12-20 23:22:14

How can I prevent a method from getting overridden in a subclass, missing a call to its superclass' implementation within?.
I know calling [super methodName]; will solve my problem sometimes.
But if somebody else was to use my parent class and overrode my method, accidentally missing to call super, what can I do?

如何防止方法在子类中被重写,从而丢失对其超类实现的调用?我知道调用[super methodName];有时会解决我的问题。但是如果其他人使用我的父类,并且重写了我的方法,不小心错过了调用super,我能做什么呢?

Some more explanations:

更多的解释:

I create a viewcontroller VC1 which has a method -(void)indexDidChange:(int)index { }. I write some actions there which I need to perform every time. and I subclass this viewcontroller named as SVC1 in it I need -(void)indexDidChange:(int)index { } for doing some other actions but at the same time the VC1 -(void)indexDidChange:(int)index { } action also need to perform. So I need to call like,

我创建了一个viewcontroller VC1,它有一个方法-(void)indexDidChange:(int)索引{}。我在那里写了一些我每次都需要执行的动作。我将这个名为SVC1的视图控制器子类化我需要-(void)indexDidChange:(int)index{}用于执行其他操作,但同时VC1 -(void)indexDidChange:(int)index{}操作也需要执行。我需要像,

 -(void)indexDidChange:(int)index { 
[super indexDidChange:index];
}

So I decide to change VC1 function like,

我决定改变VC1函数,

  -(void)indexDidChange:(int)index {
     [self currentIndexDidChange:(int)index];
 }

-(void)currentIndexDidChange:(int)index { }

And I need -(void)currentIndexDidChange:(int)index { } to override and prevent -(void)indexDidChange:(int)index { } from overriding.

我需要-(void)indexDidChange:(int)索引{}来覆盖和防止-(void)indexDidChange:(int)索引{}来覆盖重写。

Is it possible?

是可能的吗?

3 个解决方案

#1


8  

Edit: After OP rephrased the question it is clear that OP is actually NOT looking for final methods, despite the questions initial phrasing, which implied just this.

编辑:在OP重新提出问题之后,很明显OP并不是在寻找最终的方法,尽管问题是最初的措辞,只是暗示了这一点。

New (updated) answer to OP's question on method overriding safety:

According to your rephrased question you are not looking for protecting a method from being overridden at all, but rather worried about one of your subclasses overriding a method and accidently missing to include a call to super in its new implementation.

根据您重新提出的问题,您并不是要保护一个方法不被重写,而是担心您的一个子类覆盖一个方法,并且意外地丢失了在其新实现中包含对super的调用。

This however is a fairly common and widespread issue and something you're dealing with on a daily basis, without paying much attention to it.

然而,这是一个相当普遍和广泛的问题,你每天都在处理,却没有注意到它。

Every Objective-C programmer is familiar with the following method, right?

每个Objective-C程序员都熟悉以下方法,对吗?

- (void)dealloc {
    [iVar release], iVar = nil;
    [super dealloc]; //skipping this call to super is fatal!
}

And we al know that skipping the [super dealloc]; makes things get uncomfortable. (afaik the clang compiler issues a warning if dealloc lacks the call to super, …pretty handy.)

我们都知道跳过[super dealloc];让事情变得不舒服。(如果dealloc没有调用super,那么clang编译器会发出警告……非常方便。)

Despite the fact that a bad overriding of this method can have fatal consequences Apple did not choose to put any kind of security system in place here.

尽管这种方法的错误覆盖会带来致命的后果,但苹果并没有选择在这里安装任何类型的安全系统。

Instead Apple did this (as done with any other method requiring calls to super):

相反,苹果这样做了(就像其他任何需要调用super的方法一样):

  • Add a note to the method's documentation:
  • 在方法的文档中添加说明:

After performing the class-specific deallocation, the subclass method should incorporate superclass versions of dealloc through a message to super

在执行特定于类的deallocation之后,子类方法应该通过一条到super的消息合并dealloc的超类版本

  • Expect you, the programmer, to be a grown-up and responsible for what you do. And for playing by the rules (as defined by the documentation).
  • 期待你,程序员,成为一个成年人,对你所做的事情负责。并按规则进行操作(由文档定义)。

Keep in mind that - (void)dealloc is by no means an exception. There are dozens and dozens of methods of this type in Cocoa. (Take just about any derivative of - (id)init, most of the KVO observing methods, etc. just to name a few.)

记住- (void)dealloc绝不是例外。在Cocoa中有几十种这种类型的方法。(取- (id)init的任何导数,大多数KVO观察方法,等等,仅举几个例子。)

So what you should do is:

所以你应该做的是:

  1. Write a good documentation for your method. (better for your entire project, actually)
  2. 为您的方法编写一个好的文档。(实际上对你的整个项目来说更好)
  3. Add a big loud note to your method's documentation, explaining its rules.
  4. 在方法的文档中添加一个大的注释,解释它的规则。
  5. Add a note to each of your subclasses' overridden method implementations, right above the line that's calling super, telling the reader/dev to look up documentation, when in doubt of the rules. (optional)
  6. 在每个子类的覆盖方法实现中添加一个注释,在调用super的行之上,告诉读者/dev在不确定规则的情况下查找文档。(可选)
  7. Code responsibly. Otherwise, you shouldn't be coding in first place. It's your customers who will suffer from it, eventually.
  8. 代码负责。否则,您不应该首先编写代码。最终,你的客户将受到影响。

Old (pre-rephrasing) answer on archieving pseudo-final methods:

What you are asking for is the equivalent of a final function, as known from Java or C++. Unlike Java or C++, however there are no final methods in Objective-C.

您所要求的是等效于最终函数,如Java或c++所知道的。与Java或c++不同,Objective-C中没有最终的方法。

Depending on your situation there are solutions that might bring your at least near to what you're aiming for. All you'll get though is slightly better separation. You won't get any significant security from them. In Objective-C you cannot even be sure about the origin of your methods. Method swizzling allows you to exchange methods at will. With code injection you an even inject code into processes at runtime. All this is by design of Objective-C. Objective-C allows you to saw off the branch you're sitting on. Thus it demands you to act like a grown-up. As such there are no private methods either. If a method is proclaim private you as a dev are expected to behave accordingly.

根据你的情况,有一些解决方案可能会使你至少接近你的目标。你能得到的只是稍微好的分离。你不会从他们那里得到任何重要的安全保障。在Objective-C中,你甚至不能确定你的方法的起源。方法swizzle允许您随意交换方法。使用代码注入,您甚至可以在运行时将代码注入进程。这都是Objective-C的设计。Objective-C允许你从你所在的分支中看到。因此它要求你表现得像个成年人。因此,也没有私人方法。如果一个方法声明为私有,那么开发人员就会要求您这样做。

Now to possible "solutions":

现在可能的“解决方案”:

If only your super class if supposed to call the given (final) method anyway:

如果只是你的超类如果假设调用给定(最终)方法:

  1. Then Macmade's solution of making your method a pseudo-private method would work quite well. The downside of hiding method declarations though is, that calling your hidden method from subclasses will give you a compiler warning, basically preventing*(sic!)* you from calling it. (It will not prevent you from calling the method though. It will only avoid you from doing so, by throwing compiler warnings.)
  2. 然后Macmade的解决方案,使您的方法一个伪私有方法将会很好地工作。但是隐藏方法声明的缺点是,从子类调用隐藏方法会给您一个编译器警告,基本上会阻止您调用它。(但它不会阻止您调用该方法。它只会通过抛出编译器警告来避免您这样做)。

If subclasses however are expected to call the given (final) method:

如果子类期望调用给定(最终)方法:

  1. Use a delegation pattern and by this only make those methods public that are allowed to be overridden.
  2. 使用委托模式,通过这种方式只公开允许重写的那些方法。
  3. To prevent overriding at all you could use the class cluster & abstract factory patterns, which hides your implementation classes and thus preventing overriding entirely. (Apple's NSArray, NSDictionary, NSSet classes do this)
  4. 为了避免重写,您可以使用类集群和抽象工厂模式,它们隐藏了实现类,从而完全避免重写。(苹果的NSArray, NSDictionary, NSSet类做这个)

However you might notice that with Objective-C lack of protection one usually can only choose between the two: openness, protectedness, not intermix them.

然而,你可能会注意到,对于缺乏保护的Objective-C,人们通常只能在两者之间做出选择:开放,保护,而不是相互混合。

#2


4  

You can use categories in the implementation, so your methods aren't exposed in your header file.

您可以在实现中使用类别,因此您的方法不会在头文件中公开。

MyClass.m

MyClass.m

@interface MyClass( Private )

- ( void )myMethod;

@end

@implementation MyClass( Private )

- ( void )myMethod
{}

@end

@implementation MyClass

/* ... */

@end

#3


0  

If you don't declare your function in the ".h file" then its not listed, I think.

如果你没有在"h文件"那么我想它没有列出来。

#1


8  

Edit: After OP rephrased the question it is clear that OP is actually NOT looking for final methods, despite the questions initial phrasing, which implied just this.

编辑:在OP重新提出问题之后,很明显OP并不是在寻找最终的方法,尽管问题是最初的措辞,只是暗示了这一点。

New (updated) answer to OP's question on method overriding safety:

According to your rephrased question you are not looking for protecting a method from being overridden at all, but rather worried about one of your subclasses overriding a method and accidently missing to include a call to super in its new implementation.

根据您重新提出的问题,您并不是要保护一个方法不被重写,而是担心您的一个子类覆盖一个方法,并且意外地丢失了在其新实现中包含对super的调用。

This however is a fairly common and widespread issue and something you're dealing with on a daily basis, without paying much attention to it.

然而,这是一个相当普遍和广泛的问题,你每天都在处理,却没有注意到它。

Every Objective-C programmer is familiar with the following method, right?

每个Objective-C程序员都熟悉以下方法,对吗?

- (void)dealloc {
    [iVar release], iVar = nil;
    [super dealloc]; //skipping this call to super is fatal!
}

And we al know that skipping the [super dealloc]; makes things get uncomfortable. (afaik the clang compiler issues a warning if dealloc lacks the call to super, …pretty handy.)

我们都知道跳过[super dealloc];让事情变得不舒服。(如果dealloc没有调用super,那么clang编译器会发出警告……非常方便。)

Despite the fact that a bad overriding of this method can have fatal consequences Apple did not choose to put any kind of security system in place here.

尽管这种方法的错误覆盖会带来致命的后果,但苹果并没有选择在这里安装任何类型的安全系统。

Instead Apple did this (as done with any other method requiring calls to super):

相反,苹果这样做了(就像其他任何需要调用super的方法一样):

  • Add a note to the method's documentation:
  • 在方法的文档中添加说明:

After performing the class-specific deallocation, the subclass method should incorporate superclass versions of dealloc through a message to super

在执行特定于类的deallocation之后,子类方法应该通过一条到super的消息合并dealloc的超类版本

  • Expect you, the programmer, to be a grown-up and responsible for what you do. And for playing by the rules (as defined by the documentation).
  • 期待你,程序员,成为一个成年人,对你所做的事情负责。并按规则进行操作(由文档定义)。

Keep in mind that - (void)dealloc is by no means an exception. There are dozens and dozens of methods of this type in Cocoa. (Take just about any derivative of - (id)init, most of the KVO observing methods, etc. just to name a few.)

记住- (void)dealloc绝不是例外。在Cocoa中有几十种这种类型的方法。(取- (id)init的任何导数,大多数KVO观察方法,等等,仅举几个例子。)

So what you should do is:

所以你应该做的是:

  1. Write a good documentation for your method. (better for your entire project, actually)
  2. 为您的方法编写一个好的文档。(实际上对你的整个项目来说更好)
  3. Add a big loud note to your method's documentation, explaining its rules.
  4. 在方法的文档中添加一个大的注释,解释它的规则。
  5. Add a note to each of your subclasses' overridden method implementations, right above the line that's calling super, telling the reader/dev to look up documentation, when in doubt of the rules. (optional)
  6. 在每个子类的覆盖方法实现中添加一个注释,在调用super的行之上,告诉读者/dev在不确定规则的情况下查找文档。(可选)
  7. Code responsibly. Otherwise, you shouldn't be coding in first place. It's your customers who will suffer from it, eventually.
  8. 代码负责。否则,您不应该首先编写代码。最终,你的客户将受到影响。

Old (pre-rephrasing) answer on archieving pseudo-final methods:

What you are asking for is the equivalent of a final function, as known from Java or C++. Unlike Java or C++, however there are no final methods in Objective-C.

您所要求的是等效于最终函数,如Java或c++所知道的。与Java或c++不同,Objective-C中没有最终的方法。

Depending on your situation there are solutions that might bring your at least near to what you're aiming for. All you'll get though is slightly better separation. You won't get any significant security from them. In Objective-C you cannot even be sure about the origin of your methods. Method swizzling allows you to exchange methods at will. With code injection you an even inject code into processes at runtime. All this is by design of Objective-C. Objective-C allows you to saw off the branch you're sitting on. Thus it demands you to act like a grown-up. As such there are no private methods either. If a method is proclaim private you as a dev are expected to behave accordingly.

根据你的情况,有一些解决方案可能会使你至少接近你的目标。你能得到的只是稍微好的分离。你不会从他们那里得到任何重要的安全保障。在Objective-C中,你甚至不能确定你的方法的起源。方法swizzle允许您随意交换方法。使用代码注入,您甚至可以在运行时将代码注入进程。这都是Objective-C的设计。Objective-C允许你从你所在的分支中看到。因此它要求你表现得像个成年人。因此,也没有私人方法。如果一个方法声明为私有,那么开发人员就会要求您这样做。

Now to possible "solutions":

现在可能的“解决方案”:

If only your super class if supposed to call the given (final) method anyway:

如果只是你的超类如果假设调用给定(最终)方法:

  1. Then Macmade's solution of making your method a pseudo-private method would work quite well. The downside of hiding method declarations though is, that calling your hidden method from subclasses will give you a compiler warning, basically preventing*(sic!)* you from calling it. (It will not prevent you from calling the method though. It will only avoid you from doing so, by throwing compiler warnings.)
  2. 然后Macmade的解决方案,使您的方法一个伪私有方法将会很好地工作。但是隐藏方法声明的缺点是,从子类调用隐藏方法会给您一个编译器警告,基本上会阻止您调用它。(但它不会阻止您调用该方法。它只会通过抛出编译器警告来避免您这样做)。

If subclasses however are expected to call the given (final) method:

如果子类期望调用给定(最终)方法:

  1. Use a delegation pattern and by this only make those methods public that are allowed to be overridden.
  2. 使用委托模式,通过这种方式只公开允许重写的那些方法。
  3. To prevent overriding at all you could use the class cluster & abstract factory patterns, which hides your implementation classes and thus preventing overriding entirely. (Apple's NSArray, NSDictionary, NSSet classes do this)
  4. 为了避免重写,您可以使用类集群和抽象工厂模式,它们隐藏了实现类,从而完全避免重写。(苹果的NSArray, NSDictionary, NSSet类做这个)

However you might notice that with Objective-C lack of protection one usually can only choose between the two: openness, protectedness, not intermix them.

然而,你可能会注意到,对于缺乏保护的Objective-C,人们通常只能在两者之间做出选择:开放,保护,而不是相互混合。

#2


4  

You can use categories in the implementation, so your methods aren't exposed in your header file.

您可以在实现中使用类别,因此您的方法不会在头文件中公开。

MyClass.m

MyClass.m

@interface MyClass( Private )

- ( void )myMethod;

@end

@implementation MyClass( Private )

- ( void )myMethod
{}

@end

@implementation MyClass

/* ... */

@end

#3


0  

If you don't declare your function in the ".h file" then its not listed, I think.

如果你没有在"h文件"那么我想它没有列出来。