本文介绍了在Objective-C中,如何完全替换父类的方法,同时保留父方法的继承功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上我有一个类层次结构,像这样:

Basically I have a class hierarchy something like this:

NSObject
  MySpecialController
    MyExtraSpecialController

每个都有一个 init 方法,实现调用 super 首先让超类初始化自身第一,一路向上链。因为缺乏更好的术语,我会说每个类增强其超类的行为。

Each of these has an init method, and each implementation calls super first to let the superclass initialize itself first, all the way up the chain. For lack of better terminology I would say that each class "augments" its super class' behaviour.

但是让我们假设我想替换我的超类的行为完全只是因为我想为一个特定的应用程序进一步专门化,但没有杂乱的通用可重用的超类。因此,假设我有超类的亲密的知识。我想做的实际更改是用一个更具体的类类型替换一个属性。为了完全实现这个,我需要 init 方法来实例化一个适当类的 widget 的实例。所以如果我实例化一个 MySpecialController ,它的 widget 属性应该是 MySpecialWidget ;但是如果我实例化一个 MyExtraSpecialController ,它的小部件应该是 MyExtraSpecialWidget

But let's suppose I want to "replace" my super class's behaviour entirely (simply because I want to specialize it further for a particular app, but without cluttering the generic reusable super class. So it is assumed that I have intimate knowledge of the super class). The actual change that I want to do is replace a property with one of a more specific class type. To fully implement this I need the init method to instantiate an instance of widget of the appropriate class. So if I instantiate a MySpecialController, its widget property should be of type MySpecialWidget; but if I instantiate a MyExtraSpecialController, its widget should be of type MyExtraSpecialWidget:

//MySpecialController:

@interface MySpecialController : NSObject

@property (strong, nonatomic) MySpecialWidget *widget;

@end

@implementation MySpecialController

-(id)init {
    if (self = [super init]) {
        self.widget = [MySpecialWidget new];
    }
}

@end


//MyExtraSpecialController:

@interface MyExtraSpecialController : MySpecialController

@property (strong, nonatomic) MyExtraSpecialWidget *widget;

@end

@implementation MyExtraSpecialController

-(id)init {
    if (self = [super init]) {
        self.widget = [MyExtraSpecialWidget new];
    }
}

@end



这工作在 MySpecialController 工作,任何人都可以使用公共API。和 MyExtraSpecialController 也可以工作,并遵循适当的关注分离,因为它不假定超类的行为。这是将创建一个框架或库类的子类型:鲁棒和不懈的。

Now this works in the sense that MySpecialController works, and can be used by anyone with the public API. And MyExtraSpecialController also works, and follows proper separation of concerns as it assumed nothing about the superclass's behaviour. This is the type of subclass one would create of a framework or library class: robust and unassuming.

实际上发生的是,当我创建一个新的实例 MyExtraSpecialController ,它的超类首先实例化一个 MySpecialWidget ,然后立即释放该实例并将其替换为 MyExtraSpecialWidget 。当然这个工作,但是由于我已经熟悉了超类(这基本上意味着我知道它的 init 方法,所以我可以安全地替换它,而不需要调用它首先),我想避免这个问题,只实例化一个单一的小部件(它只是这样发生,创建一个小部件是非常昂贵的,并没有过早优化)。所以我想替换super的实现完全,使其不创建一个小部件,并将替换它做的所有其他基于我的内心的知识,但是,这是关键,我仍然想调用 init 进一步向上链,因为我不知道我替换的类'superclass' init 方法( NSObject 在这种情况下),因为这是一个类我没有密切的知识。

What actually happens though is that when I create a new instance of MyExtraSpecialController, its superclass first instantiates a MySpecialWidget, and then it immediately deallocates that instance and replaces it with an instance of MyExtraSpecialWidget. Sure this works, but since I DO have intimate knowledge of the superclass (which basically means that I know exactly what its init method does, so I can safely replace it without needing to call it first), I want to avoid this problem and only instantiate a single widget (it just so happens that creating a widget is really expensive and isn't premature optimization). So I want to replace super's implementation entirely so that it doesn't create a widget, and will replace everything else that it does based on my intimate knowledge, but, and this is key, I still want to call init further up the chain because I don't know what my replaced class' superclass' init method does (NSObject in this case), as this is a class I don't have intimate knowledge of.

想到的即时解决方案是使用Objective-C动态运行时获得祖父类实例,只需调用其 init (如果需要,它将调用链)绕过超级。但是每当我发现自己要做某些类似的事情,我总是想知道是否有一个更好的方法 - 从概念上讲,即替换而不是增加一个超类的方法。有没有?

The immediate solution that comes to mind is to use the Objective-C dynamic runtime to get hold of the grandparent instance, and just call its init (which will then take care of calling up the chain if it needs to), therewith bypassing super. But whenever I find myself about to do something like that I always wonder if there is a better approach altogether--conceptually speaking, i.e. to replace rather than augment a superclass' method. Is there?

推荐答案

您可以删除 self.widget init 函数并实现自定义的延迟getter函数:

You could remove the instantiation of self.widget from the init functions and implement a custom "lazy" getter function instead:

- (MySpecialWidget *)widget
{
     if (_widget == nil) {
         _wigdet = [MySpecialWidget new];
     }
     return _widget;
}

然后你可以在子类中重写这个方法。小部件将在第一次访问 self.widget 时创建,并且调用超类或子类getter。

Then you can override this method in the subclass. The widget will be created on the first access to self.widget, and either the superclass or the subclass getter is called.

这篇关于在Objective-C中,如何完全替换父类的方法,同时保留父方法的继承功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-18 20:24