前回は、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を実装してみます。