読者です 読者をやめる 読者になる 読者になる

まゆたまガジェット開発逆引き辞典

電子工作やプログラミングのHowtoを逆引き形式で掲載しています。作りたいモノを決めて学んでいくスタイル。プログラマではないので、コードの汚さはお許しを

■[iPhone開発記事]Notificationを使ってTabbarで他のタブからTableViewのセルを追加する

Notificationの続きです。
TabbarでTab1に設置したボタンを押すとTab3に設置したセルがひとつ増えます。
「Tab1に設置したボタンが押されたよ→セル増やして」の部分でNotificationを使っています。

要はボタン押したら- (void)insertNewObject:が動いてセルがひとつ増えたよ、というだけです。
セルに表示するテキストを別のTabで入力させたい場合などに使用できます。
後からテキスト入力に対応したCoreData版も作ります。

流れとしては、
0.アプリ起動
1.Tab1に設置したボタンを押す
2.Tab3のセルが増えて、セルが増えた日時を表示

これ、Tab3を最初に表示する画面にしておいて処理をすれば難しいことはないのですが、そうでない場合はすごく大変でした。「Tabbarはタブが選択されなければViewが作られない」ということをよく覚えておく必要があります。
今回最初に表示される画面はTab1のもの。
つまり、Tab3をタップしないとセルが増えないんです。

viewDidLoadやviewWillAppearでTab3→Tab1と自動で選択させる方法を試してもダメ(1クッション置かないとダメみたい)。AppDelegateにごちゃごちゃ書いてもダメ。
結局viewWillAppearでTab3を自動選択させておき、0.05秒後にTab1を選択させて起動状態に戻すということをやりました。
この方法で良いかの確証を持っていません。かなり力技です。

コードの流れとしては、
0.起動直後はTab1が表示
1.すぐ自動でTab3が選択される
2.0.05秒後Tab1が自動で選択され、起動直後の状態に戻る
3.Tab1に設置したボタンを押す
4.Tab3のセルが増えて、セルが増えた日時を表示

となります。サンプルは以下です。GitHub - prince9/TableCellAddNotification: A push on the button installed in Tab1 will add the cell of Tab3. Tab1に設置したボタンをタップするとTab3のセルがひとつ増えます

・Tab1ViewController.h

@interface Tab1ViewController : UIViewController
- (IBAction)add:(id)sender;
@end

・Tab1ViewController.m
...

//追加
- (void)viewWillAppear:(BOOL)animated {
    //アプリが起動したときにセルのあるタブをあらかじめ選択した状態にしておく。Tabbarはタブを選択して初めてViewが作られるため、アプリ起動後、セルのあるタブをタップしないでセルを追加する場合はこうする必要がある(が、この方法がいいかどうか・・・)
    //セルのあるタブを選択したことにする
    UITabBarController *controller = self.tabBarController;
    controller.selectedViewController = [controller.viewControllers objectAtIndex: 2];
    //0.05秒後に1つ目のタブ(Tab1ViewController)に戻る
    [self performSelector:@selector(delayTab) withObject:nil afterDelay:0.05f];
    
    [super viewWillAppear:animated];
}
...
//追加 セル追加の通知の作成と実行、MasterViewControllerの- (void)insertNewObject:を実行する
- (IBAction)add:(id)sender {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"P1" object:self];
}

//1つ目のタブ(Tab1ViewController)に戻る
//returns to the 1st tab. 
- (void)delayTab {
    UITabBarController *controller = self.tabBarController;
    controller.selectedViewController = [controller.viewControllers objectAtIndex: 0];
    
}
@end

・MasterViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    self.navigationItem.leftBarButtonItem = self.editButtonItem;

    /*
    UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)];
    self.navigationItem.rightBarButtonItem = addButton;
     */
    
    //追加、add 通知を受信して- (void)insertNewObject:を実行
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(insertNewObject:) name:@"P1" object:nil];

}
//追加というか変更 (NSNotification *) notificationを忘れずに
- (void)insertNewObject:(NSNotification *) notification
{
    if (!_objects) {
        _objects = [[NSMutableArray alloc] init];
    }
    [_objects insertObject:[NSDate date] atIndex:0];
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    //追加 日時の表記を変える
    //日時の書式を作成
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy年 MM/dd HH:mm"];
    
    NSDate *object = [_objects objectAtIndex:indexPath.row];
    //書式を変更
    NSString *dateString = [formatter stringFromDate:object];
    //日時を表示
    cell.textLabel.text = dateString;

    return cell;
}
...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"showDetail"]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        NSDate *object = [_objects objectAtIndex:indexPath.row];
        //追加
        DetailViewController *detailViewController = [segue destinationViewController];
        [[segue destinationViewController] setDetailItem:object];
        //追加 日時の表記を変える
        //日時の書式を作成
        NSDateFormatter *formatter2 = [[NSDateFormatter alloc] init];
        [formatter2 setDateFormat:@"yyyy年 MM/dd HH:mm"];
        //書式を変更
        NSString *dateString2 = [formatter2 stringFromDate:object];
        //日時を表示する準備(DetailViewControllerに送る)
        //send Date-data DetailViewController.
        detailViewController.myStr = dateString2;
    }
}
@end

・DetailViewController.h

@interface DetailViewController : UIViewController {
    //追加 日時受け取り用
    NSString *myStr;
}
//追加
@property (nonatomic,retain) NSString *myStr;
...

・DetailViewController.m

...
@synthesize detailDescriptionLabel = _detailDescriptionLabel;
//追加
@synthesize myStr;
...
- (void)configureView
{/* ここはコメントアウトしておく*/
}
- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
    //追加 日時表示
    _detailDescriptionLabel.text = myStr;
    [self configureView];
}