● Carbon視点でiPhone探求(2009/08/24)

  このニュースは、MOSAの会員にのみ配布されているデベロッパー向けの
  デジタルマガジンMOSADeNのに掲載された記事です。ほぼ一ヶ月遅れで
  ここに掲載されて行きます

 〜 データソースとデリゲートを実装する 〜


今回は、本アプリのビューコントローラー(RootViewController)に、テーブルビュー(UITableView)での行表示に必要とされるデータソースとデリゲートメソッドを実装してみます。テーブルビューで表示する内容は、モデル(Model)オブジェクトに保存されている画像ファイルの名称やサムネイルです。

今回は、サムネイル表示はひとまず置いておき、ファイルの名称のみをテスト的にテーブルビューに表示してみます。そのため、ドキュメント(Document)オブジェクトが管理する配列(NSMutableArray)に、モデル(Model)オブジェクトを幾つか追加することから始めます。復習として、Model.hに定義したモデルオブジェクとを見てみます。今回は、今後何かに必要かもしれないので、md_idという識別子をインスタンス変数に追加してみました。当然、これもプロパティ宣言しておきます。

@interface Model : NSObject <NSCoding>
{
  NSString  *md_name;
  NSString  *md_type;
  UIImage   *md_image;
  CGRect    md_rt;
  NSInteger  md_id;  // 今回追加した識別子
  NSUInteger  md_flag;
  NSInteger  md_kind;
  NSInteger  md_para;
}

@property(nonatomic,assign)NSInteger  md_id; // プロパティ宣言

続いて、モデルオブジェクトを配列に追加するメソッドを作成します。対象となる配列はドキュメントオブジェクトのdo_arrayプロパティですので、このメソッドはDocument.mに実装します。こちらも復習として、Document.hに定義されたドキュメントオブジェクトを再掲載しておきます。

@interface Document : NSObject
{
  NSString     *do_path;  // ドキュメントファイルパス
  NSMutableArray  *do_array; // ドキュメント配列
}

@property(nonatomic,retain)NSString     *do_path;
@property(nonatomic,retain)NSMutableArray  *do_array;

以下が、ドキュメントにモデルオブジェクトを追加するaddModelWithName:type:メソッドです。モデルオブジェクトはdo_array配列に追加されていきます。

- (Model *)addModelWithName:(NSString *)name type:(NSString *)type
{
  NSUInteger  maxid=0;
  Model     *model;

  if( model=[[Model alloc]initWithName:name type:type] ) // モデルの作成
  {
    for( Model *model1 in do_array ) // 現在の識別子の最大値を得る
    {
      if( model1.md_id > maxid )
        maxid=model1.md_id;
    }
    model.md_id=++maxid;     // 新規の識別子を設定する
    [do_array addObject:model];  // ドキュメントの配列に追加(retain)
    [model release];        // リーク防止のrelease
  }
  return model;           // 作成したモデルを返す
}

本アプリでは、SymmetryAppDelegateクラスで新規ドキュメントの作成、もしくはファイルからの読み込みを行っていますので、そのすぐ後に、ドキュメントに3つのモデルオブジェクトを追加する「テスト処理」を記述してみます。つまり、この3つのモデルのファイル名が、RootViewControllerに配置されているテーブルビューの各行に表示されれば、今回のテストは成功ということになります。

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
  if( ap_document=[[Document alloc] init] ) // ドキュメント作成
  {
    if( [ap_document load]==NO )    // ドキュメント読み込み
    {
     // ファイルの作成や読み込みが出来なかった(でエラー処理)
    }
    else
    {  // テスト的にモデルオブジェクトを3つ追加してみる

      [ap_document addModelWithName:@"Test-1" type:@"Image"];
      [ap_document addModelWithName:@"Test-2" type:@"Image"];
      [ap_document addModelWithName:@"Test-3" type:@"Image"];
    }
  }
  [window addSubview:[navigationController view]];
  [window makeKeyAndVisible];
}

続いて、 RootViewController.mへ必要とされる各種メソッドを実装していきます。まずは、前々回に説明したビューコントローラの表示開始時や終了時に呼ばれるメソッドのオーバーライドです。表示開始時には、SymmetryAppDelegateに登録されているドキュメントを得て、そのdo_arry配列をローカルのrt_arrayプロパティに代入(retain)します。また、表示終了時には、その配列プロパティにnilを代入してreleaseを実行します。

- (void)viewWillAppear:(BOOL)animated
{
  SymmetryAppDelegate *app;

  [super viewWillAppear:animated]; // スーパークラス呼び出し
               // SymmetryAppDelegateオブジェクトを探す
  app=(SymmetryAppDelegate *)[[UIApplication sharedApplication] delegate];
  self.rt_array=app.ap_document.do_array; // ドキュメントの配列を得る
}

- (void)viewWillDisappear:(BOOL)animated
{
  [super viewDidAppear:animated]; // スーパークラス呼び出し
  self.rt_array=nil;         // ローカルに確保した配列を解放
}

次は、テーブルビューのデータソースです。以下の3つのメソッドを実装することで、アプリケーションをシミュレータで起動させると、上から順番に3つの行に「 Test-1」「 Test-2」「 Test-3」と表示されるはずです。

(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
  return 1; // UITableViewのセッション数は1つのみ
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
   return [rt_array count]; // 行数はモデルの配列数と一致する
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
  Model      *model;
  UITableViewCell  *cell;
          // テーブル表示用のセルを得る(無ければ作成)
  cell=[tableView dequeueReusableCellWithIdentifier:@"ImageCell"];
   if( ! cell )
    cell=[[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"ImageCell"] autorelease];
  if( model=[rt_array objectAtIndex:indexPath.row] ) // 指定行のモデルを得る
    cell.textLabel.text=model.md_name; // 指定行にファイル名を表示
   return cell;
}

iPhone OS 2.xまでは、cell.textLabel.textの部分はcell.textと記載していました。ところが、iPhone OS 3.0においては、UITableViewCellクラスのtextプロパティが非推奨(DEPRECATED)となり、textLabelプロパティ(UILabelクラス)経由で文字列をセットするように変更されました。とりあえず、旧アクセス方法でもアプリは起動できますが、開発ターゲットがiPhone 3.0 SDKの場合には、コンパイル時にワーニング(黄色の注意)が表示されますので、ご注意ください。

最後は、テーブルビューのデリゲートです。ユーザが名称が表示されている行をタップすることで、このメソッドが実行されます。実際には、この位置に、指定されたモデルを新しいビューコントローラに引き渡して、その画像を表示させる処理を実装することになります。今回は、正しくモデルが読み込まれているかどうかをNSLog()で確認しています。


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  Model *model;

  // 行の青いセレクションを外す(アニメーション付)
  [tableView deselectRowAtIndexPath:indexPath animated:YES];

  if( model=[rt_array objectAtIndex:indexPath.row] ) // 指定行のモデルを得る
  {
    // ここで画像表示用ビューにモデルを渡して切り替える処理を実行する
    NSLog( @"%@",model.md_name ); // モデルを正しく得ているかを確認
  }
}

今回は、テーブルビューにファイル名しか表示しませんでしたが、次回は、ファイル名に加えて行の先頭にサムネイル画像を表示する予定です。その場合、使用するメモリの増加を防ぐために、オリジナル画像から小画像を作成する処理を用意する必要があります。

copyright 2009 Ottimo, Inc. All rights reserved
無断転載・引用禁止