ようやく折り返しの第5章です。
実際にコードを書かないと「何それ?」な内容も増えてきましたが、
それらをすっ飛ばしても充分に勉強になるので、このまま最後まで押しきるつもりです。
で、それから実際にアプリを作りつつ、復習ですかね。
と言うわけで、今回読む章は…
5 ビューコントローラーのパターン
5.1 ビューコントローラとは
ビューコントローラ・クラスはMVCのC(コントローラ・レイヤ)に属する。
Cocoa touch プログラミングでは、このクラスが実装の中心を占める。
ビューコントローラは1画面に1つ作成することになる。 *01これは第2章「2.4.5 コントローラレイヤ設計のパターン」でも書かれています。
5.2 ビューコントローラのライフサイクル
ビューコントローラのプログラミングは、
継承元であるUIViewControllerクラスのメソッドを上書きしながら、
機能追加して行くのが基本スタイル。
UIViewControllerの各種メソッドの呼び出しタイミングの理解が必要。
UIViewControllerのライフサイクルを図示してくれている。

5.2.1. 初期化
UIViewControllerライフサイクルのエントリーポイント。
initWithNibName:bundle と initWithCoder の2つがある。
initWithNibName:bundle は、引数としてnibファイル *02Next Interface Builder で作成されるファイル を指定して呼び出される。
initWithCoderは、NSCodingプロトコルで定義されているメソッド。
*03正直、現段階ではよくわかっていない。このあたりは実際にコーディングしながら復習する。
ポイントは、エントリーポイントが2つ存在すること。
まず、両者に共通の初期化メソッドを用意することで、初期化忘れを防ぐ。
次に、初期化時にnibファイルを指定させるのはクラスの独立性を下げる。
よって、nibファイル呼び出し自体にnibファイル名を埋め込んでしまう。
- (void)_init {
// 初期化処理
...
}
- (id)init {
// nibファイル名を指定して初期化メソッドを呼び出し。
self = [super initWithNibName:@"NibFileName" bundle:nil];
if (!self) {
return nil;
}
// 共通の初期化メソッド
[self _init];
return self;
}
注意点としては、初期化段階ではnibファイルが読み込まれていないこと。
よって、初期化段階で行う初期化処理は、nibファイルと無関係な処理に限定される。
5.2.2. nib ファイルの読み込み
UIVewContollerをビューに関連付けする場合、
nibファイルであれば、viewプロパティへの接続を行う。
nibファイルを使わない場合は、
自前でUIViewのインスタンスを用意し、
そのviewプロパティに接続を行う。
これらビューとの関連付けが行われるタイミングは、
画面表示されようとするときになる。
1)nibファイルを使用する場合
viewDidLoadメソッドの呼び出し時に行う。 *04つまりnibファイルの関連付けは、この直前に行われている
- (void)viewDidLoad {
//アウトレットの初期化
...
}
viewDidLoadの注意点は、複数回呼び出される可能性があること。
内部で初期化を行っているが、
初期化メソッドではないので、複数回呼び出しに耐えられる内容にすること。
2)nibファイルを使用しない場合
loadViewメソッドを上書きして使用する。
このメソッド内でUIViewのviewプロパティに接続。
- (void)loadView {
// UIViewのインスタンスを取得
UIView* view;
view = [[UIView alloc] initWithFrame:CGRectZero];
[view autorelease];
// view プロパティに接続
self.view = view;
}
3)nibファイルの強制読み込み
nibファイルの読み込みタイミングは画面表示されるとき。
もし、それ以前にnibファイルを読み込みたい場合は、
viewプロパティにアクセスすると、強制的に読み込むことができる。
例:RSSContentControlerというUIViewControllerの場合
// ビューコントローラをインスタンス化
RSSContentController* controller;
controller = [[RSSContentController alloc] init];
[controller autorelease];
// viewプロパティにアクセスしてnibファイルを読み込み
controller.view;
// アウトレットへの参照が有効になる
NSURLRequest* request;
request = ...;
[controller.webView loadRequest:request];
nibファイル強制読み込みの注意点は、メモリ消費量。
フレームワークが意図するより早い段階でnibファイルが読み込まれる。
5.2.3. ビューコントローラの表示
ビューコントローラが画面表示されるときに呼ばれるメソッドは以下の2つ。
・viewWillAppear:
・viewDidAppear:
viewWillAppear は、画面表示アニメーション前、
viewDidApeaer は、画面表示アニメーション後、に呼び出される。
両者とも何回も呼び出されるので、それに耐える作りにすること。
5.2.4. ビューコントローラの隠蔽
ビューコントローラが画面から隠されるとき呼ばれるメソッドは以下の2つ。
・viewWillDisAppear:
・viewDidDisAppear:
viewWillDisAppear は、画面表示アニメーション前、
viewDidDisApeaer は、画面表示アニメーション後、に呼び出される。
それぞれviewWillAppear:、viewDidAppear:と対になっている。
当然、両者とも何回も呼び出されるので、それに耐える作りにすること。
表示メソッドと異なるのは、画面隠蔽時だけでなく、
画面破棄のときも呼ばれること。
よって、隠蔽と破棄のどちらで呼ばれても耐えられる作りにすること。
5.2.5. view の解放
ビューコントローラが解放されるときに呼ばれるメソッドは以下の2つ。
・didReceiveMemoryWarning
・viewDidUnload
didReceiveMemoryWarning は、システムメモリ不足時に呼び出される。
viewDidUnload は、アウトレットの解放に使用される。
両者は連続しており、
システムメモリの不足によってdidReceiveMemoryWarningが呼ばれた後、
表示されていないビューコントローラを解放すべくviewDidUnloadを呼ぶ。
viewDidUnload はviewDidLoad と対になっている。
用途は先にも述べたように、アウトレットの解放。
よって、ビューコントローラ破棄のdeallocメソッドでも必要とされる。
1)アウトレット解放メソッド
- (void)_releaseOutlets {
// アウトレットを解放
[_tableView release], _tableView = nil;
[_feedItem release], _feedItem = nil;
[_refreshItem release], _refreshItem;
}
2)アウトレット解放メソッドを、viewDidUnload および dealloc で呼ぶ
- (void)viewDidUnload {
// アウトレット解放
[self _releaseOutlets];
}
- (void)dealloc {
// アウトレット解放
[self _releaseOutlets];
// その他、インスタンス変数を解放
...
// 親クラスのdeallocを呼び出し
[super dealloc];
}
アウトレット解放の注意点は、
アウトレット以外のインスタンス変数を解放してしまわないこと。
でないと、ビューの再表示を行う際に、
nibファイルだけでは画面復旧できなくなる。
メモリ不足の状態シミュレートはiPhoneシミュレータで可能。
[ハードウェア]→[メモリ警告をシミュレート]でOK。
【おまけ】細っかい事ですが
今回のタイトル、「コントローラー」と末尾が伸ばされています。
しかし、文中では「コントローラ」と末尾を伸ばしていません。
この手の表記ゆれ、普段はあまり気にしないのですが、
今回の様に勉強しながら読んでいる場合は、結構不安にさせられます。
何が不安って「同義語」です。
同じ意味の言葉を異なる表記で書かれていたりするんじゃないかと、おっかなくなるんです。
内容に対する知識不足が原因なわけですが、
この点は自分でも気をつけて行かないとならない内容ですね。
「それは修辞として成り立つ同義語か?」
「読み手に混乱を招いていないか?」
細っかい事ですが、気になりましたとさ。
[現在、3/17 05:35 眠たくなってきた。今日の仕事どうしよう。orz]

