第5章 【ビューコントローラのパターン】の続きを読む ーあるいは、焦燥感とのジレンマー

投稿者: | 2011/03/19

さて、まだ5章が続きます。
「Cocoa touch プログラミングの中心」とうたわれているだけあって、
ページ数も多いんです。 *01まあ、内容の重要度とページ数は必ずしも比例しませんが。

iOS開発におけるパターンによるオートマティズム

木下 誠 (単行本 – 2011/2/9)
¥ 2,940


と言うわけで、今回読む章は…

5 ビューコントローラーのパターン

の続き。

5.3 ビューコントローラの配置の仕方

ビューコントローラの生成と利用について、実例を交えて解説されている。

5.3.1. ナビゲーションコントローラに入れる

UINavigationControllerクラスを利用して、ビューコントローラの管理を行う。
pushViewController:animated:と言うメソッドを使って、
ナビゲーションコントローラが管理する階層の最後にビューコントローラを追加する。

実例

    // コントローラをインスタンス化する
    RSSItemListController* controller;
    controller = [[RSSItemListController alloc] init];
    
    // 自動解放する
    [controller autorelease];
    
    // ナビゲーションコントローラに追加
    [self.navigationController pushViewController:controller animated:YES];

ポイントは、自動解放してから追加している点。
こうすることで、
ビューコントローラの管理をナビゲーションコントローラに任せる。
結果、自身は参照を保持する必要がなくなる。

注意点は、ビューコントローラからの通知の受け取り。
これについては「7.2.5. コントローラ間の通知のパターン」を参照。 *02本の記述では、「8.2.5.」 となっているが、これは誤記。

5.3.2. モーダルビューとして表示する

UIViewControllerのpressModalViewController:animated:メソッドを使う。
これもナビゲーションコントローラに入れてしまい、自身では参照を保持しない。

実例

- (IBAction)feedAction {
    // コントローラを作成
    RSSFeedListController* controller;
    controller = [[RSSFeedListContoller alloc] init];
    // 自動解放する
    [controller autorelease];
    
    // ナビゲーションコントローラ作成
    UINavigationController* navController;
    navController = [[UINavigationController alloc] 
                    initWithRootViewController:controller];
    // こっちも自動解放
    [navController autorelease];
    
    // モーダルビューとして表示する
    [self presentModalViewController:navController animated:YES];
}

問題は、モーダルビューの隠蔽。
通常はdismissModalViewControllerAnimated:メソッドを、
モーダルビューとして表示されているコントローラに対して呼び出す。

が、この本では、モーダルビューの隠蔽もビューを作成したコントローラに持たせる。
上記の実例はRSSChannelListControllerがRSSFeedListControllerを、
モーダルビューとして表示している。
この場合、ビューの隠蔽もRSSChannelListControllerに行わせたい。

そのためには、コントローラ間で通知を行う仕組みがいる。
これも詳細は「7.2.5. コントローラ間の通知のパターン」を参照。 *03ここも、本の記述では、「8.2.5.」 と誤記。
どうも7章が8章になってしまっているようだ。

5.3.3. 手動で配置する

UIViewのaddSubview:を使用する。
ただし、ビューコントローラとして守らなければならない手順がある。

実例

    // コントローラを作成
    _controller = [[RSSFeedListController alloc] init];
    
    // 大きさを設定
    CGRect rect;
    rect = self.view.bounds;
    _controller.view.frame = rect;
    
    // ビューを追加
    [self.view addSubview:_controller.view];
    
    // UIViewControllerのメソッドを呼び出し
    [_controller viewWillAppear:NO];
    [_controller viewDidAppear:NO];

ポイントは、まず大きさを調整すること。
その後viewWillAppear:とviewDidAppear:を呼び出す。
これにより、ビューコントローラとして必要な処理が動く。

注意点としては、ライフサイクル管理も自前で行なってやる必要があること。
適切なタイミングでコントローラを破棄する様にする。

5.4 ナビゲーションアイテム

ナビゲーションバーの両端位置に配されるボタン。
具体的には、
UINavigationItemクラスの、
leftBarButtonItem と rightBarButtonItem のプロパティ。
操作しやすい場所にあるため、
ユーザーインタフェースとしては、かなり重要。

5.4.1. UIBarButtonItem の作成と更新

作成方法は2つ。
Interface Builder で作成する方法と、ソースコード中で作成する方法。

Interface Builder は、
ライブラリからドラッグ&ドロップでボタンを配置できるなど、
グラフィカルに作成できる。

ソースコード中で作成する場合は、
viewDidLoadのメソッドで作成する。
UIBarButtonItemには、initWithImage:style:target:action や、
initWithTitle:style:target:actionなどのメソッドで初期化を行う。

実例

- (void)_updateNavigationItem:(BOOL)animated {
    // ナビゲーションアイテムの設定
    [self.navagationItem setLeftBarButtonItem:_feedItem animated:animated];
    [self.navigationItem setRightBarButtonItem:_refreshItem animated:animated};
}

最初の呼び出しはviewWillAppearになる。

- (void)viewWillAppear:(BOOL)animated {
    ...
    
    // 画面を更新
    [self _updateNavigationItem:animated];
    
    ...
}

上記の様にviewWillAppear内で呼び出されることで、
画面更新時に確実にナビゲーションアイテムも更新される。

_updateNabigationItemのanimatedフラグは、
viewWillAppear:のanimatedフラグを利用するため。

5.4.2. 編集ボタンとedittingプロパティ

編集ボタンあUIViewControllerのeditButtonItemメソッドで取得できる。
これはUIViewControllerのeditingプロパティと連動しており、
ボタンのタイトルが「編集(Edit)」と「完了(Done)」で切り替わる。

当然、編集画面への切り替えが必要。
setEditing:animatedメソッドを上書きして実装する。

- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
    // 親クラスのメソッドを呼び出す
    [super setEditing:editing animated:animated];
    
    // 画面を更新する
    [self _updateNavigationItemAnimated:animated];
}

_updateNavigationItemAnimated:では、
editingプロパティの値に応じてナビゲーションアイテムを更新する。
実例

- (void)_updateNavigationItemAnimated:(BOOL)animated {
    // 編集モードの場合
    if ( self.editing ) {
        // ナビゲーションアイテムの設定
        [self.navigationItem setLeftBarButtonItem:nil animated:animated];
        [self.navigationItem setRightBarButtonItem:nil animated:animated];
    }
    // 通常モードの場合
    else {
        // ナビゲーションアイテムの設定
        [self.navigationItem setLeftBarButtonItem:_addItem animated:animated];
        [self.navigationItem setRightBarButtonItem:_addItem animated:animated];
    }
}
5.4.3. キャンセルと保存

編集と並んで、定番のナビゲーションアイテム。
ポイントは、いきなりモデルオブジェクトを操作しないこと。
保存ボタンsaveActionと、キャンセルボタンcancelActionを用意し、
データ編集時は、ビューのインスタンス値のみを編集。
saveActionが呼ばれたときに、始めてモデルオブジェクトを編集する。

実例

- (IBAction)saveAction {
    // 編集中のチャンネルを取得
    RSSChannel* channel;
    channel = _channel;
    
    // チャンネルがない場合は新たに作成
    if ( !channel ) {
        // 新規チャンネルを作成
        channel = [[RSSChannel alloc] init];
        [channel autorelease]:
        
        // チャンネルを追加
        [[RSSChannelManager shareManager] addChannel:channel];
    }
    
    // タイトルを設定
    channel.title = _titleTextField.text;
    
    // URLを設定
    channel.feedUrlString = _urlTextFields.text;
    
    // チャンネルの配列を保存する
    [[RSSChannelManager shareManager] save];
    
    ...
}

5.5 ツールバー

基本的にナビゲーションアイテムと同様。
状況に応じたボタンの使用と、余計なメモリの使用回避。
そのため、更新は独立したメソッドで行う。
実例

- (void)_updateToolbarItems:(BOOL)animated {
    // ツールバーを表示
    [self.navigationController setToolbarHidden:NO animated:animated];
    
    // ツールバーアイテムの設定
    NSArray* toolbarItems;
    toolbarItems = [NSArray arrayWithObjects:_merkItem, nil];
    [self setToolbarItems:toolbarItems animated:animated];
}

注意点は、ツールバーアイテムの表示⁄非表示 の切り替えも、
このメソッド内で行っている点。
ツールバー表示のビューから非表示のビューに切り替わるときも、
このメソッドを呼び出してやることで、ツールバーを非表示にしてやることができる。

【おまけ】はじめてみたは良いけれど

「iOS開発におけるパターンによるオートマティズム」 *04毎度思うが、長いタイトルだわー。 を読み、ブログに書こう!
と思い立って、考えなしに実行してから、はや20日。

結局、ぐだぐだと本の内容をなめるだけの記事が続いて、かなり後悔。

本の内容への理解が不足しているので、たぶん的外れな事もいっぱい書いている。
そもそも、他人様に読んでもらう作りになっていない。 *05本の内容を垂れ流しているだけの記事になっている気もしている。

いったん止めて、もっと練った書き方をした方が良いとも考えるが、
まずは、このまま1周するつもり。

その上で、見せ方含めて考えた2周目が書ければ良いなー。
などと夢想しつつ、早くひと通りを終えたい今日この頃です。


脚注

脚注
01 まあ、内容の重要度とページ数は必ずしも比例しませんが。
02 本の記述では、「8.2.5.」 となっているが、これは誤記。
03 ここも、本の記述では、「8.2.5.」 と誤記。
どうも7章が8章になってしまっているようだ。
04 毎度思うが、長いタイトルだわー。
05 本の内容を垂れ流しているだけの記事になっている気もしている。

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください