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

时间:2013-07-16 06:29:21

标签: objective-c class initialization override designated-initializer

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

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

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

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

4 个答案:

答案 0 :(得分:13)

@justin基本上就是重点。

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

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

答案 1 :(得分:2)

  

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

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

例如,-initWithDomain:code:userInfo:NSError指定的初始化程序; [[NSError alloc] init]可能会返回一个合理的描述性错误吗?

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

请注意,在某些情况下,您的类可以同时支持两个初始值设定项。在这种情况下,只需重新安装@interface指定的初始化程序。这足以记录指定的初始化程序。或者将初始化程序或初始化程序集记录为指定的初始值设定项,这将在逻辑上使任何超类的指定初始化程序无效。

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


实施例1,:

// 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

修改

在评论中澄清了问题。

当您简单地覆盖超类声明的初始值设定项时:

  

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

除非你的类有初始化要执行,否则你不需要显式覆盖超类的指定初始值设定项。

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

假设:

@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

答案 2 :(得分:0)

基本上说如果一个班级有iniWithSomethingDomething,那么最好做一个

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

在您自己的初始化程序中

答案 3 :(得分:0)

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

在你的实现中就像这样。

制作指定的init

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

然后在覆盖超级

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