Ios 自我初始化。。与超级初始化。。。在子类中

Ios 自我初始化。。与超级初始化。。。在子类中,ios,objective-c,init,super,Ios,Objective C,Init,Super,我有一个UIViewContoller子类baseviewcontroller。它有一个名为-initWithStyle:的方法。如果我将该类子类化为subsaviewcontoller, -[subsaviewcontroller init]应该是什么样子 我的代码: - (id)init { self = [self initWithStyle:kGreenStyle]; if (self) { // stuff } return self;

我有一个
UIViewContoller
子类
baseviewcontroller
。它有一个名为
-initWithStyle:
的方法。如果我将该类子类化为
subsaviewcontoller
-[subsaviewcontroller init]
应该是什么样子

我的代码:

- (id)init
{
    self = [self initWithStyle:kGreenStyle];
    if (self) {
        // stuff
    }
    return self;
}
subsaviewcontroller
中,我没有
initWithStyle:

我的应用程序在上面的
-init
中随机崩溃,我检查了属于
BaseViewController
子类的其他视图控制器,它们使用
self=[super-initWithStyle:kGreenStyle]
,并正常工作。解释是什么?

你应该使用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;
}

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

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

当使用Interface Builder定义具有资源(即nib文件或序列)的视图控制器时,将调用第二种形式。手动创建视图控制器时,可以使用第一个表单

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

// 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
时,它最终将使用
nil
参数调用
initWithNibName:bundle:

另见:参考:

您的问题的另一种可能的解决方案: 提供初始化自定义视图控制器的方法的一种方法是使用“便利类方法”。在这种情况下,您不需要重写指定的初始值设定项,而是在子类中提供属性

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

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

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

首先,是的,了解指定的初始值设定者。它们很重要,而且是CouchDeveloper 强调这一点是正确的

其次,没有任何东西可以阻止
UIViewController
的子类 完全不同的指定初始值设定者(最好是一个)由您自己选择。 如果在Interface Builder外部创建
UIViewController
s, 正如OP可能正在做的那样,
-initWithNibName:Bundle:
而且
-initWithCoder:
变得很愚蠢

苹果说:

定义子类时,必须能够识别超类的指定初始值设定项,并通过发送给super的消息在子类的指定初始值设定项中调用它。您还必须确保以某种方式覆盖继承的初始值设定项

鉴于此,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完全可以自由地将
    [subsaviewcontroller init]
    声明为指定的初始值设定项,只要他遵守规则
最后,未经请求的OP建议:

  • 假设这些不是你原来的文章中的拼写错误,你应该始终将 类名的第一个字母<代码>基本视图控制器,而不是
    基本视图控制器
    。 你可以逆水行舟,成语是当你 变成一个十足的坏蛋;到那时,我敢打赌你不会想的

再加上一点,当您以
nil
作为nibName调用
init
时,则
nibName
属性设置为nil。在这种情况下,运行时要么使用您在
loadView
中创建的视图,要么根据中描述的启发式搜索nib文件。这就是为什么如果您有一个
MyViewController
和一个
MyViewController.xib
可以使用普通
init
,它将使用关联的nib文件。@Abizern谢谢Abizern,这是有用的信息。因此,为了创建自定义视图控制器,最好创建一个“便利类方法”,它完全封装了这些细节(nib名称和bundle参数)。请参阅我的答案以了解更多细节。@Greg我想道歉:我之前关于这个答案是错误的声明过于仓促。事实上,如果基类正确实现,如@claybridges所示,即
initWithStyle:
是一个合适的指定初始值设定项,它将工作。
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