前回からの続き。
さて、Todoリストをの作り方で僕が一番悩んだのはタイトルや日付、内容といった複数の要素をどーやって保存してるんだろう?ってこと。
いろいろと調べて行き着いたのは、一つのtodoをNSDictionaryで作って、それをNSMutableArrayに入れて保存しているらしい。いわゆる入れ子構造なのかな?
色々とやりかたは有るんだろうけどそんな感じで進めていく。
まずは、StoryboardのDetail画面が寂しいのでテキストフィールドとテキストビューを設置する。
言うまでもなくUITextFieldは一行の入力画面で、UITextViewは複数行の入力画面です。
できればautoLayoutで位置の調整をしておきましょう。
んで、2画面にして、プロパティを作ります。
テキストフィールドはtitleField、テキストビューはbodyTextViewにしました。
これらのタイトルと内容を保持するNSDictionary形式のtodoプロパティを作りましょう。
ちなみにこれはMasterViewControllerからも使うのでヘッダファイルDetailViewController.hに作ります。
#import <UIKit/UIKit.h> @interface DetailViewController : UIViewController //detilViewでの内容を保存するtodo @property (strong, nonatomic) NSDictionary *todo; @end
さて、コードを書いていきます。
先ほど中身を削除したconfigureViewを再利用します。
Master画面の+ボタンで来た場合、todoの中身はありません。
なので無いことを確認して、新しく、todoを作って入力して表示させます。
- (void)configureView { if (!self.todo) { //todoが何もない、新規で来た場合。 _todo = @{ @"title":@"タイトル", @"body":@"内容"}; self.titleField.text = _todo[@"title"]; self.bodyTextView.text = _todo[@"body"]; } }
内容を入力したら戻らないといけません。
保存ボタンを付けてMaster画面に戻れるようにします。
前回の+ボタンのようにbarButtonItemをDetail画面の右上に設置します。
このボタンからセグエの復路を辿るのですが、MasterViewControllerにunwindToMasterメソッドがないとExitに接続できません。
なのでMasterViewController.mにunwindToMasterメソッドを追加します。
- (IBAction)unwindToMaster:(UIStoryboardSegue *)segue { }
そしてunwindToMasterメソッドに接続します。
今回は元々あるMaster-Detail Applicationを使っているので保存せずに戻る為のボタンがすでに有りますが、自分で新たにViewを作った場合など、セグエを戻るルートが複数ある場合、ルートによってidentifierを設定しておいた良い場合があります。
一応今回もidentifierをsaveTodoとして設定しておきます。
詳しくはsegueで戻る時のidentifierの設定。こっちを見てね。
Master画面に戻る前に書いた内容をtodoに入れます。
prepareForSegueメソッドはセグエの移動の前に呼ばれるメソッドです。
# pragma segueで戻る前の処理。 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { _todo = @{@"title": self.titleField.text,//タイトル @"body": self.bodyTextView.text};//内容 }
保存からMaster画面に戻ったらまずunwindToMasterメソッドに入ります。
すでにあるセルを呼び出して変更した場合と、新規でtodoを作ってきた場合で処理が変わるのですが、まずは新規でtodoを作ってきた場合の処理を書きます。
戻ってきたらDetailViewControllerのtodoを呼び出してinsetrNewTodoに渡します。
insertNewTodoでは、NSMutableArrayプロパティのobjectsがあるかどうか確認してなければ作ってからその中に格納しています。
- (IBAction)unwindToMaster:(UIStoryboardSegue *)segue { //segueの遷移先から帰ってきた時。 if ([segue.identifier isEqualToString:@"saveTodo"]) { //遷移先のビューを取得 DetailViewController *controller = (DetailViewController *)segue.sourceViewController; [self insertNewToDo:controller.todo]; } } - (void)insertNewToDo:(id)sender { if (!_objects)//もしオブジェクトがなかったら { _objects = [[NSMutableArray alloc] init];//生成初期化 } //objects配列に新規辞書配列todo(sender)をいれる。 [_objects insertObject:sender atIndex:0]; NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; }
最後に- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath メソッドでテーブルに表示される内容を変更します。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; NSDictionary *todo = _objects[indexPath.row]; cell.textLabel.text = todo[@"title"]; return cell; }
これで起動すれば+ボタンでDitail画面に行って、保存して戻ってくることが出来ます。
ただ、まだセルを選択してDitail画面に行った場合の処理を書いていないので正常動作しません。