我正在读一本有指导原则的书:
“如果一个类声明了一个与其超类不同的指定初始值设定项,则必须重写超类的指定初始值设定项以调用新的指定初始值设定项”
据我所知,这个指南换句话说,如果我将我的类子类化为其超类,并且我的子类有一个与des不同的指定初始化器。它的超类的初始化程序,然后在我的子类中,我必须覆盖我的超类的指定初始化程序,并在其内部调用我的子类的指定初始化程序。
这是真的吗?我们必须一直这样做吗?谢谢。
答案 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: @""];
}