3

我想创建一个 UINavigationController 的子类,它总是以相同的根控制器开始。没什么特别的,所以(对我来说)像这样重写 init 方法是非常有意义的:

- (id) init {
   rootController = [[MyController alloc] init];

   if (self = [super initWithRootViewController:rootController]) {
       // do some more initialization
   }

   return self;
}

这显然会产生问题,因为[super initWithRootViewController]会调用[UINavigationController init],这当然是我们重写的init方法,所以会发生无限递归。

我不想创建具有不同名称的 init 方法,例如“initCustom”。

目前我只能想出一个解决方案,但我真的很讨厌这种 hack:

- (id) init {
   if (initCalled)
       return self;

   initCalled = YES;

   rootController = [[MyController alloc] init];

   if (self = [super initWithRootViewController:rootController]) {
       // do some more initialization
   }

   return self;
}

所以我的问题是:有没有更好的方法来处理这个问题?我确定我遗漏了一些非常明显的东西,但我没有看到。

编辑:我想这样做的原因,可以在下面我的评论之一中看出:

我想创建一个始终以特定视图控制器开头的导航控制器。我想对班级的消费者隐藏这一点。不需要暴露的东西就不用暴露了。让生活更轻松,代码更简洁(发明封装的原因之一,对吧?)

4

4 回答 4

10

首先 UINavigationController 不适合子类化。

无论如何,最简单的方法是覆盖initWithRootViewController:

- (id) initWithRootViewController:(UIViewController) viewController {
   return [super initWithRootViewController:[[[MyController alloc] init] autorelease]];
}

你最好不要自动释放 MyController,但你理解这个想法......

于 2009-12-11T16:02:40.860 回答
4

我在这里阅读了很多关于为什么会有这样的行为,但没有真正干净的解决方案。正如Gcamp指出的那样,文档明确告诉我们不要继承 UINavigationController。

所以我开始思考:如果不允许子类化,那就只剩下封装了,这似乎是解决这个问题的一个可接受的解决方案:

@interface MyNavigationController : UIViewController {
   UINavigationController *navController;
   UIViewController *myController;
}

执行:

@implementation MyNavigationController

- (id) init {
   if (self = [super init]) {
       myController = [[MyController alloc] init];
       navController = [[UINavigationController alloc] initWithRootViewController:myController];
   }

   return self;
}

- (void) loadView {
   self.view = navController.view;
}

- (void) dealloc {
   [navController release];
   [myController release];
   [super dealloc];
}

@end

我不是 Objective-C 方面的专家,所以这可能不是最好的方法。

于 2009-12-11T18:14:27.897 回答
3

你真的测试过这段代码吗?为什么要[super initWithRootViewController]调用重写的init方法?它将调用该[super init]方法,即(如您所说)[UINavigationController init](不是您的 overriden init)。

于 2009-12-11T15:57:10.950 回答
3

只需覆盖并使用 -initWithRootViewController: 指定初始化程序。您可以将 nil 作为参数传递

- (id) initWithRootViewController:(UIViewController*)ignored {
   rootController = [[MyController alloc] init];

   if (self = [super initWithRootViewController:rootController]) {
       // do some more initialization
   }

   return self;
}

在这里阅读更多:http: //developer.apple.com/mac/library/documentation/cocoa/conceptual/ObjectiveC/Articles/ocAllocInit.html#//apple_ref/doc/uid/TP30001163-CH22-106376

于 2009-12-11T16:03:36.677 回答