● Carbon視点でiPhone探求(2009/11/30)

  この記事は、MOSAの会員にのみ読むことができるデベロッパー向けの
  ウェブサイトMOSADeN Onlineのに掲載された記事です。ほぼ一ヶ月
  遅れでここに掲載されて行きます

 〜 登録画像の削除と順序変更 〜


前回は、ImageViewControllerへの切り替え方法を変更し、ボタンやセグメントボタンを配置したツールバーを用意しました。今回から、実際に対称処理を実装する前の最後の準備、テーブルビューの各行に並んだ画像(モデル)の削除、順序変更、名称変更といった編集処理を実装していきます。

まず最初に、登録された画像の削除と順序変更を実装してみます。こうした編集機能はテーブルビュー(UITableView)の能力を使います。まず、テーブルビューを表示しているビューコントローラー(RootViewController)において、ナビゲーションバーの左側に「編集」ボタンを表示させます。これは、 RootViewController クラスのviewDidLoadメソッドをオーバラードすることで実現します。

- (void)viewDidLoad // ビューコントローラのビューが読み込まれた
{
  [super viewDidLoad];
  self.navigationItem.leftBarButtonItem=self.editButtonItem; // 編集ボタンを追加
}

続いて、テーブルビューのデータソースメソッド(UITableViewDataSource)を2つ追加します。これにより、テーブルビューの各行の削除や移動を個別に制御できるようになります。

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath // 行が編集可能どうかの判断を返す
{
  return YES;
}

- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath // 行が移動可能かどうかの判断を返す
{
  return YES;
}

最初は指定行の編集(今回は削除)を許すかどうかの判断を返すデータソースです。このメソッドがYESを返せば、そのindexPath.rowで指定される行は編集可能と判断されます(デフォルトはYES)。「編集」ボタンをタップするとボタン表示が「完了」に変わり、行の左側に赤丸マイナスアイコンが表示されます。それをタップすると右側に「削除」ボタンが表示されます。2つ目は、指定行の移動を許すかどうかの判断を返すデータソースです。このメソッドがYESを返せば、セルの右側に移動可能を示すアイコンが表示されます(デフォルトはNO)。今回は行単位の個別制御はしませんので、すべての行に対して無条件でYESを返しています。

  

以下が削除処理を実装するテーブルビューのデータソースメソッドです。ちなみに、削除ではなく挿入処理を実装する時には、editingStyleがUITableViewCellEditingStyleInsertかどうかを判断することになります。削除が実行されて、登録画像がすべてなくなった場合にはsetEditing: animated:メソッドを呼び出して編集モードを終了し、「完了」ボタンを「編集」ボタンに戻しておきます。

- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
                                                   // 行の挿入(+)か削除(ー)の修正に反応する
{
  Model  *model;
  
  if( editingStyle==UITableViewCellEditingStyleDelete ) // (ー)ボタンを押した時(削除)
  {
    if( model=[rt_array objectAtIndex:indexPath.row] ) // モデルを得る
    {
      [[self document] removeModel:model]; // モデルと画像ファイルを削除する
      [self.tableView reloadData]; // テーブルビューを描画し直す
      if( [rt_array count]==0 )
        [self setEditing:NO animated:YES]; // 行がひとつも無ければ編集終了
    }
  }
}

行番号( indexPath.row)から指定されたモデルを得て、ドキュメントのモデル配列からそれを削除します。まずは、メインドキュメントを簡単に得るためのdocumentメソッドをRootViewControllerクラスに用意してみました。

- (Document *)document // メインドキュメントを返す
{
  SymmetryAppDelegate  *app;
  
  app=[[UIApplication sharedApplication] delegate]; // アプリケーションデリゲート
  return app.ap_document; // メインドキュメントを返す
}

そして、Documentクラスには指定モデルを削除するremoveModel:を、Modelクラスには、そのモデルに登録されているJPEG画像ファイルを削除するdeleteImageメソッドを実装します。deleteImageメソッドでは、モデルの名前とID番号からファイルパス名を作成し、それを物理的に削除します。

- (void)removeModel:(Model *)model // 指定モデルを削除
{    
  [model deleteImage]; // 登録画像ファイルの削除
  [do_array removeObject:model]; // ドキュメント配列から削除する
}

- (void)deleteImage // モデルに登録されている画像ファイルを削除する
{
  NSString  *str,*name,*path;
  NSError   *err=nil;
  
  str=[NSString stringWithFormat:@"%@-%d",md_name,md_id];
  name=[str stringByAppendingString:@".jpg"]; // 画像ファイル名の作成      
  path=getDocumentPath( name );       // パス名の作成
  if( isExistPath( path )==YES )
    [[NSFileManager defaultManager] removeItemAtPath:path error:&err];  
}

  

ちなみに、「編集」ボタンをタップしなくても対象行をスワイプすることで「削除」ボタンを表示させることも可能です。

  

次は行の移動処理を実装するテーブルビューのデータソースメソッドです。 メッセージとして渡されたsourceIndexPath.rowとdestinationIndexPath.rowから移動元と移動先のモデルを得て、それをDocumentクラスに実装されているswapModelSource:destination:メソッドに渡します。

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath // 行が移動させられた時に呼ばれる
{
  Model    *smodel,*dmodel;
  NSUInteger  sid,did;
  
  sid=sourceIndexPath.row;
  did=destinationIndexPath.row;
  if( sid!=did ) // ソースとデスティネーションが異なる場合のみ
  {      
    if( smodel=[rt_array objectAtIndex:sid] ) // ソースモデルを得る
    {
      if( dmodel=[rt_array objectAtIndex:did] ) // デストネーションモデルを得る
      {
        [[self document] swapModelSource:smodel destination:dmodel];
                    // ソースとデストネーションモデルの交換
        self.rt_array=[self document].do_array; // テーブルビューのモデル配列再構築
      }
    }
  }
}

こちらが、Documentクラスに用意したswapModelSource:destination:メソッドです。NSArrayクラスのremoveObject:とinsertObject:atIndex:メソッドを使い、配列内オブジェクトの交換を実現しています。

- (void)swapModelSource:(Model *)smodel destination:(Model *)dmodel // モデル配置を変更(交換)
{
  NSUInteger  sid,did,dir;
  
  sid=[do_array indexOfObject:smodel]; // ソースモデルのインデックス番号を得る
  did=[do_array indexOfObject:dmodel]; // ターゲットモデルのインデックス番号を得る
  if( did > sid )
    dir=1; // 後方へ移動
  else
    dir=0; // 前方へ移動
  [smodel retain]; // retainしないと本当に削除されてしまう!
  [do_array removeObject:smodel];
  did=[do_array indexOfObject:dmodel]; // ターゲットモデルのインデックス番号を得る
  [do_array insertObject:smodel atIndex:did+dir]; // 次にインサートする
  [smodel release]; // 追加した後はreleasesしておく!
}

今回は、画像(モデル)の削除と順序変更を実装してみました。次回は、テーブルビューに並んだ画像の名称変更を解説したいと思います。そのために、画像情報の詳細を表示する新しいUIViewControllerを実装してみます。

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