首页 文章

覆盖超类的指定初始值设定项

提问于
浏览
9

我正在读一本有指导原则的书:

“如果一个类声明了一个与其超类不同的指定初始值设定项,则必须重写超类的指定初始值设定项以调用新的指定初始值设定项”

据我所知,这个指导就是说,如果我将我的类子类化为它的超类,并且我的子类有一个与des不同的指定初始化器 . 它的超类的初始化程序,然后在我的子类中,我必须覆盖我的超类的指定初始化程序,并在其内部调用我的子类的指定初始化程序 .

这是真的?我们必须一直这样做吗?谢谢 .

4 回答

  • 0

    @justin基本上就是重点 .

    Objective-C中的方法是遗传的 . 这意味着如果超类具有初始化方法(初始化器只是方法),并且您的子类没有覆盖它,那么您的子类将继承该超类的初始化方法 . 这意味着人们总是可以在子类的对象上调用超类的初始化器(继承和子类型多态的基本结果) . 但这可能不是你所期望的 . 超类的初始化程序可能无法完成您的类所需的所有初始化 .

    这就是为什么你应该覆盖超类的初始化器 . 如果您不希望人们在您的类的对象上使用该初始化程序,则应该在该初始化程序中引发异常 . 否则,您应该覆盖它以对您的类进行任何适当的初始化 .

  • 2

    这是真的吗?我们必须一直这样做吗?

    就个人而言,我认为这是一个糟糕的指导方针 . 当你指定了一个更严格的指定初始化器(例如引入参数的初始化器)时,实现超类'指定的初始化器(做任何有意义的事情)是不合逻辑的 .

    例如, -initWithDomain:code:userInfo:NSError 的指定初始值设定项; [[NSError alloc] init] 可以返回一个合理的描述性错误吗?

    如果有的话,私下覆盖'已删除'的初始化程序并将其视为程序员错误来调用,但不要假装客户端可以使用除指定的初始化程序之外的初始化程序 .

    请注意,在某些情况下,您的类可以同时支持两个初始值设定项 . 在这种情况下,只需重新声明 @interface 's designated initializers. This is sufficient to document a designated initializer. Either that, or document an initializer or set of initializers as designated initializers, which would logically invalidate any superclass'指定的初始值设定项 .

    当然,初始化程序应该在其初始化时调用其中一个超类'指定的初始值设定项 .


    第Ex.I:

    // implicitly adds a designated initializer. -init is still valid:
    @interface MONObject : NSObject
    - (instancetype)initWithString:(NSString *)pString;
    @end
    

    例2:

    // redefines the designated initializer. -init is not valid:
    @interface MONObject : NSObject
    // MONObject's designated initializer
    - (instancetype)initWithString:(NSString *)pString;
    @end
    

    例3:

    // define all designated initializers:
    @interface MONObject : NSObject
    // MONObject's designated initializers:
    - (instancetype)init;
    - (instancetype)initWithString:(NSString *)pString;
    @end
    

    EDIT

    问题在评论中澄清 .

    当您简单地覆盖超类声明的初始化程序时:

    这是真的吗?我们必须一直这样做吗?

    Unless your class has initialization to perform, you do not need to explicitly override the superclass' designated initializer.

    您的实例将被初始化为具有归零内存 .

    鉴于:

    @interface MONObject : NSObject
    
    - (instancetype)initWithString:(NSString *)pString;
    
    @property (nonatomic, copy, readwrite) NSString * string;
    
    @end
    
    
    @implementation MONObject
    
    // if @property string should be initialized to nil, you may omit -[MONObject init]
    // otherwise, initialize self here:
    - (instancetype)init
    {
     // call super's designated initializer:
     self = [super init];
     // test it:
     if (nil == self) return nil;
     // init your state
     _string = @"(null)";
     return self;
    }
    
    - (instancetype)initWithString:(NSString *)pString;
    {
     // call super's designated initializer:
     self = [super init]; // << will not call -[MONObject init]
     // test it:
     if (nil == self) return nil;
     // init your state
     _string = pString.copy;
     return self;
    }
    
    @end
    
  • 0

    它基本上是说如果一个类有 iniWithSomethingDomething ,那么最好做一个

    self = [super initWithSomethingSomeThing:......]
    

    在你自己的初始化程序中

  • 13

    我理解它,如果你的类有一个指定的init,你想要覆盖超级init,所以它调用你指定的init .

    在你的实现中有点像这样 .

    做你的指定初始化

    -(id) initWithName:(NSString *)aName 
    {
        self = [super init];
        if (self){
            [self setName:aName];
        }
        return self;
    }
    

    然后在覆盖超级时调用它

    -(id) init
    {
        return [self initWithName: @""];
    }
    

相关问题