当前位置:  开发笔记 > IOS > 正文

使用超类初始化程序初始化类

如何解决《使用超类初始化程序初始化类》经验,为你挑选了1个好方法。

我有两个班,一个接一个的子类(比如AnimalDog).超类有一些初始化器(比方说initAnimal),子类有一些初始化器(比方说initDog).问题是完全合法(从编译器的角度来看)做类似的事情Dog *adog = [[Dog alloc] initAnimal],即.使用超类初始化程序初始化类.我不喜欢这个,因为子类可以有一些我想确保初始化的额外实例变量.查看头文件可以解决这个问题,但有一种简单的方法可以让编译器检查一下吗?我有一种感觉,我错过了一些非常明显的东西,但我不能把手指放在它上面:-)

更新:initDoginitAnimal不是最好的例子.我的意思是两个非常不同的初始化器(比如initfor AnimalinitWithFurfor Dog).如果我希望每只狗都分配一些毛皮,我会将毛皮作为初始化器的一部分,这样就没有人可以获得没有皮毛的狗对象了.但是后来用超类错误地初始化实例仍然很容易init,然后我就被软管了.

感谢您提出指定的初始化程序,杰森.之前我没有想过,但我可以重载超类的指定初始化程序并在那里设置一些合理的默认值.但是我仍然更愿意,如果我能以某种方式使用其他初始化程序而不是类本身的那些非法 - 更多的想法?



1> Jason Coco..:

通常在Objective-C中,您为每个类创建一个指定的初始化程序,然后子类使用相同的初始化程序.因此,您只需使用init,而不是使用initAnimal和initDog.然后,dog子类将定义自己的init方法,并在其父类中调用指定的初始化程序:

@implementation Dog
-(id)init
{
    if( (self = [super init]) ) {  // call init in Animal and assign to self
        // do something specific to a dog
    }
    return self;
}
@end

您实际上不必指定initDog和initAnimal,因为该类是在赋值的右侧声明的...

更新:我在答案中添加以下内容以反映问题中的其他信息

有许多方法可以确保子类不会调用除指定初始化程序之外的初始化程序,并且最终选择的方式将主要基于整个设计.Objective-C的一个好处是它非常灵活.我将在这里举两个例子来帮助你入门.

首先,如果创建的子类具有与其父类不同的指定初始化程序,则可以重载父级的初始化程序并抛出异常.这将让程序员立即知道,他们已经违反了您的课协议......但是,应当指出的是,你应该有一个非常好的理由这样做的,它应该是非常有据可查的是,子类可以不使用与超类相同的初始化程序.

@implementation Dog
-(id)init
{
    // Dog does not respond to this initializer
    NSAssert( false, @"Dog classes must use one of the designated initializers; see the documentation for more information." );

    [self autorelease];
    return nil;
}

-(id)initWithFur:(FurOptionsType)furOptions
{
    if( (self = [super init]) ) {
        // do stuff and set up the fur based on the options
    }
    return self;
}
@end

另一种方法是让初始化程序更像原始示例.在这种情况下,您可以将父类的默认init更改为始终失败.然后,您可以为父类创建一个私有初始值设定项,然后确保每个人都在子类中调用适当的初始值设定项.这个案子显然更复杂:

@interface Animal : NSObject
-(id)initAnimal;
@end

@interface Animal ()
-(id)_prvInitAnimal;
@end

@interface Dog : Animal
-(id)initDog;
@end

@implementation Animal
-(id)init
{
    NSAssert( false, @"Objects must call designated initializers; see documentation for details." );

    [self autorelease];
    return nil;
}

-(id)initAnimal
{
    NSAssert( [self isMemberOfClass:[Animal class]], @"Only Animal may call initAnimal" );

    // core animal initialization done in private initializer
    return [self _prvInitAnimal];
}

-(id)_prvInitAnimal
{
    if( (self = [super init]) ) {
        // do standard animal initialization
    }
    return self;
}
@end

@implementation Dog
-(id)initDog
{
    if( (self = [super _prvInitAnimal]) ) {
        // do some dog related stuff
    }
    return self;
}
@end

在这里,您可以看到Animal and Dog类的界面和实现.Animal是指定的顶级对象,因此会覆盖NSObject的init实现.任何在Animal或任何Animal的子类上调用init的人都会收到断言错误,并将其引用到文档中.Animal还在私有类别上定义私有初始值设定项.私有类将保留您的代码,Animal的子类在调用super时会调用此私有初始化程序.它的目的是在Animal的超类(在本例中为NSObject)上调用init,并进行可能需要的任何通用初始化.

最后,Animal的initAnimal方法的第一行是断言接收器实际上是Animal而不是某个子类.如果接收者不是Animal,则程序将因断言错误而失败,程序员将被引用到文档中.

这些只是您可以根据具体要求设计某些内容的两个示例.但是,我强烈建议您考虑一下您的设计约束,看看您是否真的需要这种类型的设计,因为它在Cocoa和大多数OO设计框架中都是非标准的.例如,您可以考虑制作各种动物根级对象,而只需要一个动物协议,要求所有各种"动物"对某些动物通用信息做出反应.这样,每个动物(以及Animal的真正子类)可以自己处理它们的指定初始化器,并且不必依赖于以这种特定的非标准方式行为的超类.

推荐阅读
手机用户2502851955
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有