self init ..与super init ...在子类中

时间:2014-03-20 09:18:45

标签: ios objective-c init super

我有一个UIViewContoller子类BaseViewControler。它有一个名为-initWithStyle:的方法。如果我将类继承为SubBaseViewContoller-[SubBaseViewController init]应该是什么样的?

我的代码:

- (id)init
{
    self = [self initWithStyle:kGreenStyle];
    if (self) {
        // stuff
    }
    return self;
}

SubBaseViewController我没有initWithStyle: 并且我的应用程序随机地与上面的-init一起崩溃,我检查了其他视图控制器,它们是BaseViewController的子类,并且他们使用self = [super initWithStyle:kGreenStyle]并且工作。解释是什么?

3 个答案:

答案 0 :(得分:4)

UIViewController两个指定的初始值设定项:

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle;

- (instancetype)initWithCoder:(NSCoder *)aDecoder;

当Interface Builder用于定义带有资源的View Controller时,将调用第二个表单,即nib文件ore segues。手动创建视图控制器时,可以使用第一种形式。

您可以按如下方式覆盖这些初始值设定项:

// Designated initializer
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
{
    self = [super initWithNibName:nibName bundle:nibBundle];
    if (self) {
        ; // your initialization
    }
    return self;
}

// Designated initializer
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        ; // your initialization
    }
    return self;
}

注意:从资源创建时,不会调用方法init。当您自己调用init时,它最终会使用initWithNibName:bundle:个参数调用nil

另请参阅:参考:Multiple Initializers and the Designated Initializer

您问题的另一种可能解决方案:

提供初始化自定义视图控制器的方法的一种方法是使用"便捷类方法"。在这种情况下,您不需要覆盖指定的初始值设定项,而是在子类中提供属性

方便类方法可能如下所示:

// MyViewController
+ (instancetype) myViewControllerWithStyle:(Style)style 
{
    // Possibly get the bundle and the nib name (or leave it nil)
    ...
    // Invoke a designated initializer with suitable parameters:
    MyViewController* viewController = [[MyViewController alloc] initWithName:nibName
                                                                       bundle:bundle];
    viewController.style = style;
    return viewController;
}

答案 1 :(得分:2)

你应该使用super而不是self:

- (id)init
{
    self = [super initWithStyle:kGreenStyle];
    if (self) {

    }
    return self;
}

如果你这样做,你就强迫父类进行它应该做的所有初始化。如果你想在子类中的init方法中做一些事情,你可以在这里添加它:

- (id)init
{
    self = [super initWithStyle:kGreenStyle];
    if (self) {
        // do some stuff you need to do in subclass initialisation
        // for example init variable specific just for that class (not parent class)
    }
    return self;
}

答案 2 :(得分:1)

这是Greg&CouchDeveloper的答案的综合。 但实际上,这是对格雷格答案的辩护。

首先,是的,了解指定的初始化程序。它们很重要,还有CouchDeveloper 强调这一点是正确的。

其次,没有什么能阻止UIViewController的子类拥有 您自己选择的完全不同的指定初始值设定项(最好是一个)。 如果要在Interface Builder之外创建UIViewController, 因为看起来OP可能正在做,-initWithNibName:Bundle:的首要地位 而-initWithCoder:变得愚蠢。

Apple说this

  

定义子类时,必须能够识别超类的指定初始化程序,并通过消息指向子类的指定初始化程序。您还必须确保以某种方式覆盖继承的初始值设定项。

鉴于此,OP的BaseViewController可能是这样的:

const NSUInteger kDefaultStyle = 0; // just to have something to use

@implementation BaseViewContoller

// No longer valid for *this* class.
// Should have one for -initWithCoder: too, but elided for this example.
- (instancetype)initWithNibName:(NSString *)nibNameOrNil
                         bundle:(NSBundle *)nibBundleOrNil
{
    [self doesNotRecognizeSelector:_cmd];
    return nil;
}

// New designated initializer for *this* class.
// This should call the superclass's designated initializer.
- (instancetype)initWithStyle:(NSUInteger)style
{
    // use the designated initializer of the superclass to init
    if ((self = [super initWithNibName:nil bundle:nil])) {
        // stuff
    }

    return self;
}

// in *other* initializers, you *should* call *your* class's
// designated initializer.
- (instancetype)init
{
    return [self initWithStyle:kDefaultStyle];
}

@end

鉴于此,我认为CouchDeveloper"这是错误的"在评论中呼唤 格雷格的答案本身就是错误的。这是因为:

  • BaseViewController是看不见的,因此我们可能知道指定的初始化程序是什么,无论其超类如何。
  • OP已经指出-[BaseViewController initWithStyle:] 指定的初始化程序
  • OP完全可以自由地声明[SubBaseViewController init]作为指定的初始化程序,只要他遵守规则。

最后,对OP的未经提出建议:

  • 假设原帖中没有拼写错误,您应始终大写 班级名字的第一个字母。 BaseViewController,而不是baseViewController。 你可以和成语游泳 成为总坏蛋;到那时,我会打赌你不想。