9

我正在读一本有指导方针的书:

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

据我了解,这条准则换句话说是,如果我将我的类从它的超类中子类化,并且我的子类有一个指定的初始化器,它与 des 不同。它的超类的初始化程序,然后在我的子类中我必须覆盖我的超类的指定初始化程序,并在其中调用我的子类的指定初始化程序。

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

4

4 回答 4

13

@justin 基本上是正确的。

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

这就是为什么你应该重写超类的初始化器。如果您不希望人们在您的类的对象上使用该初始化程序,您应该在该初始化程序中抛出异常。否则,你应该重写它来为你的类做任何适当的初始化。

于 2013-07-17T22:09:02.033 回答
2

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

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

例如-initWithDomain:code:userInfo:isNSError的指定初始化器;可以[[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
于 2013-07-16T07:14:03.017 回答
0

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

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

在您自己的初始化程序中

于 2013-07-16T06:52:39.893 回答
0

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

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

进行指定的初始化

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

然后在覆盖超级时调用它

-(id) init
{
    return [self initWithName: @""];
}
于 2013-07-16T07:48:11.910 回答