TableViewその2

さて、昨日作った編集可能なTableViewをもとに、誕生日リストを作ってみる。

基本は、昨日の内容に、これこれを組み合わせるだけである。
昨日作ったプロジェクトを変更する形で進める。

名前と日付を入力する子ビューを追加

"File"->"New"->"New File..."を選択、"UIViewController subclass"を選び次へ、"Subclasss of"で"UIViewController"を選び、"With XIB for user interface"にチェックを入れて次へ、ファイル名は"ChildViewController"とする。

子ビューに部品を配置

"ChildViewController.xib"を開き、Text Field、Date Picker、Round Rect Buttonを適当に配置する。
Date PickerはModeを"Date"にしておく。
保存後、"ChildViewController.h"を開き、以下のようにメソッド、プロパティを追加する。


@interface ChildViewController : UIViewController {
IBOutlet UITextField* textfieldName;
IBOutlet UIDatePicker* datepickerBirthday;
}

- (IBAction) setNameAndBirthday;
@property ( retain, nonatomic ) UITextField* textfieldName;
@property ( retain, nonatomic ) UIDatePicker* datepickerBirthday;

@end

"ChildViewContorller.m"の行頭に@synthesizeを追加

@implementation ChildViewController

@synthesize textfieldName;
@synthesize datepickerBirthday;

追加したプロパティは"viewDidLoad"で初期化、"viewDidUnload"でreleaseしておく。
保存後にもう一度"ChildViewController.xib"を開き、作ったメソッド、プロパティをそれぞれの部品と接続する。
Text Field -> textfieldName
Date Picker -> datepickerBirthday
Round Rect Button -> setNameAndBirthday
更に、Textfieldのdelegateを"File's owner"にする。
(ここは毎回忘れるので、要注意)

textfieldのdelegateを設定

"ChildViewController.h"に"プロトコルを追加した上で、"ChildViewController.m"に以下を追加。


- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
[ textField resignFirstResponder ];
return YES;
}

親ビューへのdelegateの実装

まず、delegateを使用する側の実装。
"ChildViewController.h"


#import
@protocol TableViewEXViewControllerDelegate;

@interface ChildViewController : UIViewController {
IBOutlet UITextField* textfieldName;
IBOutlet UIDatePicker* datepickerBirthday;
id parentDelegate;
}

- (IBAction) setNameAndBirthday;
@property ( assign, nonatomic ) id parentDelegate;
@property ( retain, nonatomic ) UITextField* textfieldName;
@property ( retain, nonatomic ) UIDatePicker* datepickerBirthday;

@end

@protocol TableViewEXViewControllerDelegate
- (void) setName: (NSString*) stringName setBirthday: (NSDate*) dateBirthday;
@end

"ChildViewController.m"

- (IBAction) setNameAndBirthday
{
[ parentDelegate setName: textfieldName.text setBirthday: datepickerBirthday.date ];
[ self dismissModalViewControllerAnimated: YES ];
}
"ChildViewController.m"の行頭には、@synthesize parentDelegate;を追加する。
これでRound Rect Buttonを押すとDelegateが呼ばれ、モーダルビューが閉じる。
引き続き親側の実装。
"RootViewController.h"

#import
#import "ChildViewController.h"

@interface RootViewController : UITableViewController {
NSString numOfCells;
}

- (void) setName:(NSString *)stringName setBirthday:(NSDate *)dateBirthday;

@end

これで入れ物は整った。
しかしこれではModelがないのである。
最後に、名前を格納する配列、誕生日と名前を紐付ける辞書をModelとして作成する。

名前と誕生日の情報を追加、削除できるようにする

"RootViewController.h"に名前を格納する配列"arrayName"と名前から誕生日を引く辞書"mdicNameAndDate"を、メンバ変数として加える。


#import
#import "ChildViewController.h"

@interface RootViewController : UITableViewController {
NSMutableDictionary* mdicNameAndDate;
NSMutableArray* arrayName;
}

@property ( retain, nonatomic ) NSMutableDictionary* mdicNameAndDate;
@property ( retain, nonatomic ) NSMutableArray* arrayName;

- (void) setName:(NSString *)stringName setBirthday:(NSDate *)dateBirthday;

@end

とした上で、"RootViewController.m"の"viewDidLoad"に初期化、"viewDidUnload"に解放を加える。
その上で、まず@synthesizeを追加。

#import "RootViewController.h"
#import "ChildViewController.h"

@implementation RootViewController

@synthesize mdicNameAndDate;
@synthesize arrayName;

numberOfRowsInSectionで名前の数から行数を設定するようにする、"+1"としてあるのはその行を追加行とするため。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ( section == 0 ) return [ arrayName count ] + 1;
else return 0;
}
cellForRowIndexPathで名前の数の行には名前と誕生日を表示する。
誕生日はcurrentLocaleに従い、DateFormatterを設定して、NSString化する。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
// cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}

// Configure the cell.
if ( indexPath.section == 0 )
{
if ( indexPath.row < [ arrayName count ] )
{
cell.textLabel.text = [ arrayName objectAtIndex: indexPath.row ];
NSDateFormatter* dfBirthday = [ [ NSDateFormatter alloc ] init ];
[ dfBirthday setLocale: [ NSLocale currentLocale ] ];
[ dfBirthday setDateStyle: NSDateFormatterMediumStyle ];
[ dfBirthday setTimeStyle: NSDateFormatterNoStyle ];
cell.detailTextLabel.text = [ dfBirthday stringFromDate:
[ mdicNameAndDate objectForKey:
[ arrayName objectAtIndex:indexPath.row ] ] ];
}
else
{
cell.textLabel.text = [ NSString stringWithFormat: @"" ];
cell.detailTextLabel.text = [ NSString stringWithFormat: @"" ];
}
}
return cell;
}

editingStyleForRowAtIndexPathで名前の行は削除ボタンを、最終行は挿入ボタンを表示するようにする。

- (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ( indexPath.row == [ arrayName count ] ) return UITableViewCellEditingStyleInsert;
else return UITableViewCellEditingStyleDelete;
}
commitEditingStyleで、削除の場合には辞書、配列の順でオブジェクトを削除、挿入の場合にはChildViewContorllerをインスタントして、モーダルビューとして表示する。

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source.
[ mdicNameAndDate removeObjectForKey: [ arrayName objectAtIndex: indexPath.row ] ];
[ arrayName removeObjectAtIndex: indexPath.row ];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[ self.tableView reloadData ];
}
else if (editingStyle == UITableViewCellEditingStyleInsert)
{
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
ChildViewController* childVC = [ [ ChildViewController alloc ] init ];
childVC.parentDelegate = self;
[ self presentModalViewController: childVC animated: YES ];
[ childVC release ];
}
}
最後にdelegateのメソッドを実装

- (void) setName:(NSString *)stringName setBirthday:(NSDate *)dateBirthday
{
[ arrayName addObject: stringName ];
[ mdicNameAndDate setObject: dateBirthday forKey: stringName ];
[ self.tableView reloadData ];
}
以上。