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 メソッドであるため、無限再帰が発生します。

「initCustom」のような別の名前の init メソッドを作成したくありません。

現在、思いつく解決策は 1 つしかありませんが、この種のハックは本当に嫌いです。

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

   initCalled = YES;

   rootController = [[MyController alloc] init];

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

   return self;
}

私の質問は次のとおりです。これを処理するより良い方法はありますか? 非常に明白な何かが欠けていると確信していますが、それはわかりません。

編集:以下の私のコメントの1つに見られるように、私がこれをやりたい理由:

常に特定のビュー コントローラーで始まるナビゲーション コントローラーを作成したいと考えています。これをクラスの消費者から隠したい。公開する必要のないものを公開する必要はありません。生活がずっと楽になり、コードがずっときれいになります (カプセル化が発明された理由の 1 つですよね?)

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]呼び出す必要があるのはなぜですか? それは(あなたが言ったように) (あなたの overriden ではありません)であるメソッドinitを呼び出します。[super init][UINavigationController init]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 に答える