FMDBで簡単写真アルバムを作ろう Part.7 ~【iPhone】SQLiteのデータを取り出してTableViewに表示~

前回:FMDBで簡単写真アルバムを作ろう Part.6 ~【iPhone】UITextField,UIActionSheet,UIImagePickerControllerとメモ、写真の保存~


簡単写真アルバムのソースコードGitHubからどうぞ
ー>https://github.com/ics-hiro/SelfPhotoLibrary


前回はNewViewControllerをつくり、メモと画像を保存しました。

今回はViewController、一番のポイントはホーム画面でこれらのデータを取り出して表示するところです。

UIViewControllerでTableViewを実装する

UIViewControllerでTableViewを実装して、データの表示を行います。

つまり、UITableViewControllerのサブクラスとして作成するのではなく、UIViewControllerの上にTableViewをのっけます。

私はこの方法でしかTableViewを実装しなくなりました、というよりUITableControllerのサブクラスでTableViewを作成しなければならないほどの理由がないからです。

理由としてはAppleのドキュメント、「iOS Table Viewプログラミングガイド」にも書かれてあります。

該当部分は、29ページに書かれていて、引用させていただきますと、

注: 管理対象のビューが複数のサブビューで構成されており、その中の1つがTableViewの場合は、Table Viewを管理するためにはUITableViewControllerのサブクラスではなく、UIViewController
のサブクラスを使用すべきです。UITableViewControllerクラスのデフォルトの動作では、NavigationBarとTab Barの間の(これら両方が存在する場合)画面一杯にTable Viewを表示します。
UITableViewControllerのサブクラスではなくUIViewControllerのサブクラスを使用してTableViewを管理することにした場合は、ヒューマンインターフェイスガイドラインに適合するように、前述のいくつかのタスクを実行する必要があります。Table Viewを表示する前にTable View内の選択をクリアするために、deselectRowAtIndexPath:animated:を呼び出して選択中の行(存在する場合)をクリアするviewWillAppear:メソッドを実装します。Table Viewの表示が完了したら、TableViewにflashScrollIndicatorsメッセージを送信することでScroll Viewのスクロールインジケータを点滅させなければなりません。それには、UIViewControllerのviewDidAppear:メソッドをオーバーライドします。


UIViewControllerのサブクラスを使用してTableViewを実装すべき理由の具体例では、たとえばTableView以外にもボタンを設置したいとか、TableViewの大きさを調整して、ほかの部品も設置したいとか、広告を設置したいとか、そういった感じですね。


では、実際に実装しましょう。

まずはデリゲートを宣言。

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITableViewDelegate,UITableViewDataSource> //<-2つ追加

@end

ViewController.m

@interface ViewController ()

// 別クラスとアクセスはしないので、プラベートに宣言
@property (retain, nonatomic) UITableView *tableView;

@end

@implementation ViewController
{
    @private
    NSMutableArray *titleArry;
    NSMutableArray *contentsArry;
}
@synthesize tableView = _tableView; //<-synthesizeして、ゲッターとセッターを生成
- (void)viewDidLoad
{
    [super viewDidLoad];
	self.title = @"Photo Library";
    self.navigationController.navigationBar.tintColor = [UIColor blackColor];
    UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(make_new_contents)];
    self.navigationItem.rightBarButtonItem = button;
    

    /*---TableViewの設置---*/
    _tableView = [[UITableView alloc] init];
    _tableView.frame = CGRectMake(0, 0, 320, 460-44); //TableViewの大きさ
    _tableView.dataSource = self;
    _tableView.delegate = self;
    _tableView.rowHeight = 90.0; // セルの高さ
    [self.view addSubview:_tableView];
    
}

あとは、TableViewに必要なメソッドを実装する必要があります。
全体の解説で順番が前後しないようにして進んで行きたいと思うので、
TableViewのメソッドについてはその都度の解説にします。

viewWillAppearを実装して、ViewControllerが呼ばれるたびにデータを更新する

// Viewが呼ばれるたびにデータとテーブルの更新
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    titleArry = [[NSMutableArray alloc] init ]; //タイトルを格納するための可変配列
    contentsArry = [[NSMutableArray alloc] init ]; //画像を格納するための可変配列
    
    [DataModels selectTitle:titleArry]; //titleフィールドを取り出す
    [DataModels selectContents:contentsArry]; //contentsフィールドを取り出す
    
    
    [_tableView reloadData]; //テーブルをリロードして更新
}

保存したメモ、つまり写真のタイトルとなる文字列ですね、
これを取り出して格納するのがtitleArryです。

保存した画像を取り出して格納するのがcontentsArryです。


どういった処理でSQLiteファイルからデータを取り出すかというと、
データの出し入れ関連はDataModelsクラスをつくったんでしたね。

まずはtitleフィールドを取り出すコードをみてみましょう。

DataModels.m

+ (NSMutableArray *)selectTitle :(NSMutableArray *)array
{
    NSArray*    paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES );
    NSString*   dir   = [paths objectAtIndex:0];
    FMDatabase* db    = [FMDatabase databaseWithPath:[dir stringByAppendingPathComponent:DB_FILE_NAME]];
    [db open];
    
	
    FMResultSet*    results = [db executeQuery:SQL_SELECT];
    
    NSString*       titleData;
	
    while( [results next] )
    {
        titleData = [results stringForColumn:@"title"]; //titleフィールドを取り出す
        [array addObject:titleData];
    }
	

    [db close];
	
    return array; //データが入った配列を最後に返す
}
  1. 最初の三行でDBのパスを取得。
  2. DBをオープンして、DBにクエリした結果をresultsに代入。
  3. titleDataにtitleフィールドのデータ(文字列)を代入して、titleDataをarrayにaddする。
  4. DBをクローズする
  5. arrayを返す


contentsフィールドに関しても基本的に同じですが、NSData型でデータをいれていてBLOBなので、
dataForColumnになっているところに注意。

DataModels.m

+ (NSMutableArray *)selectContents :(NSMutableArray *)array
{
    NSArray*    paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES );
    NSString*   dir   = [paths objectAtIndex:0];
    FMDatabase* db    = [FMDatabase databaseWithPath:[dir stringByAppendingPathComponent:DB_FILE_NAME]];
    
    [db open];
	
    FMResultSet*    results = [db executeQuery:SQL_SELECT];
    
    NSData*       contentsData;
	
    while( [results next] )
    {
	contentsData = [results dataForColumn:@"contents"]; //<-dataForColumnであることに注意!
        [array addObject:contentsData];
    }
	
    [db close];
	
    return array;
}

視覚的に図解しますと、


TableViewの行数 numberOfRowsInSection

タイトルの数と画像の数、どちらも一緒なのでcontentsArryでもいいです。
配列の要素の数だけ行数を設定します。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return titleArry.count;
}

TableViewのセクション数 numberOfSectionsInTableView

セクション分けで特別なにかする整理するわけではないので、セクションの数は1つ。

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

TableViewのセルに表示する内容 cellForRowAtIndexPath

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
    }
    
    //セルに表示する内容
    cell.textLabel.text = [titleArry objectAtIndex:indexPath.row];
    cell.imageView.image = [[UIImage alloc] initWithData:[contentsArry objectAtIndex:indexPath.row]];
    
    return cell;
}

「cell.textLabel.text」と、「cell.imageView.image」はおなじみですね。
indexPath.rowでセルに順番に表示させます。

NSDataからUIImageへ変換

セルに画像を表示するところで、

cell.imageView.image = [[UIImage alloc] initWithData:[contentsArry objectAtIndex:indexPath.row]];

というのがありました。
ここでNSDataからUIImageへ変換しています。
画像はNSDataでデータベースに格納しているので、それを使う際にはUIImageに戻す必要があります。




簡単写真アルバムアプリ記事一覧
FMDBで簡単写真アルバムを作ろう Part.1 ~メモが書ける写真アルバムをつくる~
FMDBで簡単写真アルバムを作ろう Part.2 ~Xcode4.3,SingleViewApplication,FMDB準備~
FMDBで簡単写真アルバムを作ろう Part.3 ~必要なファイルを追加して整理しよう~
FMDBで簡単写真アルバムを作ろう Part.4 ~NavigationBarと画面遷移~
FMDBで簡単写真アルバムを作ろう Part.5 ~【iPhone】SQLiteのデータを出し入れするためのクラスをつくる~
FMDBで簡単写真アルバムを作ろう Part.6 ~【iPhone】UITextField,UIActionSheet,UIImagePickerControllerとメモ、写真の保存~
FMDBで簡単写真アルバムを作ろう Part.7 ~【iPhone】SQLiteのデータを取り出してTableViewに表示~
FMDBで簡単写真アルバムを作ろう Part.8 ~【iPhone】TableViewの画面遷移、異なるView間での値の受け渡し~
FMDBで簡単写真アルバムを作ろう Part.9 ~【iPhone】TableViewのセルを削除、commitEditingStyle ~
FMDBで簡単写真アルバムを作ろう 最終章 ~簡単写真アルバムの完成~


======================
当ブログ管理人のツイッターこちら
◎フォローしてくださると泣いて喜びます!ツイッター上で当ブログの質問などにもできるだけお答えしますし、役に立つiPhoneアプリ開発情報もつぶやきます。個人的なご依頼(たとえば、プログラミングの家庭教師、Skypeレッスンをしてくれないか、iPhoneアプリ開発の勉強会ってやってるの、とかですね)でもかまいません。
スカイプレッスンについて
開発をしているとその都度ぶつかる問題があると思いますが、検索で調べてもなかなかわからない、あるいは調べても非常に時間がかかる場合があると思います。開発者のみなさんもお忙しいと思いますので、私のレッスンを受けながら開発を進めていただけると、大幅にお時間を短縮できます。加えて、iPhoneアプリ開発の基礎、応用が身につき、今後の開発もスムーズに進められます

お問い合わせはツイッター、またはhiyoshimarukoアットマークgmail.comまでお願いします。(アットマークを@にしてください)お待ちしております!