我有一个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]
并且工作。解释是什么?
答案 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
是看不见的,因此我们可能知道其指定的初始化程序是什么,无论其超类如何。-[BaseViewController initWithStyle:]
是指定的初始化程序[SubBaseViewController init]
作为指定的初始化程序,只要他遵守规则。最后,对OP的未经提出建议:
BaseViewController
,而不是baseViewController
。
你可以和成语游泳
成为总坏蛋;到那时,我会打赌你不想。