DiarySystemと落ちるアプリ

DiarySystem

日記帳みたいなものを作った。

今回のテーマは…


1. ナビゲーションコントローラと(UINavigationController)と
  タブバーコントローラ(UITabBarController)を同時に使う。
2. データベースを使う。

ということで日記帳。
完成図はこんな感じ。

タブバーコントローラを使って、List、Query(Select)、Insert、Deleteというモードを切り替えて、各モードはナビゲーションコントローラを使って画面遷移する。

ナビゲーションコントローラとタブバーコントローラ

この2つを共存させるってどうするんだろう?というところから始めた。
ナビゲーションコントローラの基本的な使い方はこんな感じ。

window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
RootViewController *rootViewController = [[RootViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];

[window addSubview:navigationController.view];
[window makeKeyAndVisible];

windowに直接置くイメージ。
続いて、タブバーコントローラの使い方はこんな感じ。

window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
NSMutableArray *viewControllers = [[NSMutableArray alloc] init];
[viewControllers addObject:myViewController];
[viewControllers addObject:yourViewController];
[viewControllers addObject:hisViewController];
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = viewControllers;

[window addSubview:tabBarController.view;
[window makeKeyAndVisible];

こちらもwindowに直接置くイメージ。

じゃあ、これら2つを同時に使いたい場合どうすればいいの?
結論としては、NSArray(NSMutableArray)にナビゲーションコントローラをまとめて、タブバーコントローラのインスタンスのviewControllersプロパティに代入する、です。実際に書くとこんな感じ。

window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

navigationControllers = [[NSMutableArray alloc] init];  // ナビゲーションコントローラの入れ物
[navigationControllers
 addObject:[[UINavigationController alloc] initWithRootViewController:[[ListTabViewController alloc] init]]];  // 追加
[navigationControllers
 addObject:[[UINavigationController alloc] initWithRootViewController:[[QueryTabViewController alloc] init]]];  // 追加
[navigationControllers
 addObject:[[UINavigationController alloc] initWithRootViewController:[[InsertTabViewController alloc] init]]];  // 追加
[navigationControllers
 addObject:[[UINavigationController alloc] initWithRootViewController:[[DeleteTabViewController alloc] init]]];  // 追加

tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = navigationControllers;  // ナビゲーションコントローラ達をタブバーコントローラにセットする
	
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];

分かってしまえば納得だけど、最初どうすればいいのか分からなかったのでメモメモ。

SQLite

iPhoneプログラミングでデータベースを使う場合SQLiteを使うことになる。…で、Objective-CSQLiteを簡単に使うためのラッパークラスFMDBというものがあるのでそれを使ってみた。以下導入方法。


1. https://github.com/ccgus/fmdbから以下のファイルをダウンロードし、
  プロジェクトのOther Sourcesに追加する。
 ・FMDatabase.h/m
 ・FMDatabaseAdditions.h/m
 ・FMResultSet.h/m
2. ヘッダファイルをインポート
3. libsqlite3.0.dylibライブラリを追加する

使い方はこちらのサイトを参考にしました。

落ちるアプリ

Queryを実装したときにアプリが落ちまくるバグ。結果のテーブルビューからクエリ入力画面に戻るところで確実に落ちる。エラーも出なくて原因不明だったのだけど、突然落ちるバグはメモリリーク関係であることが多いらしいので、allocとreleaseの対応を丁寧にチェック。その結果FMDatabase *fmdb_というクラスメンバ変数をdeallocメソッドでreleaseしてしまっていたのがいけなかった。オライリー本でそういう例ばかりだったから、クラスメンバ変数は何でもかんでもdeallocでreleaseしてたけど、そうとも限らないらしい。というか、そういうものはクラスメンバ変数にするのが適切じゃないのかなぁ。

[追記]
FMDatabaseの初期化メソッドdatabaseWithPathの定義を見たらautoreleaseが付いていた。autoreleaseしてあるインスタンスは明示的にreleaseしてはいけないんですね(^_^;)