Help us understand the problem. What is going on with this article?

【自分メモ】ARC環境下での、delegateを用いたView・Controller間でのデータ受け渡し

More than 5 years have passed since last update.

ARC環境下で、delegateを用いてデータの受け渡しを実装します。
今回はStoryboardは使わず、.xib で実装します。
具体的には、以下の機能を実装します。

1. 親Viewで子Viewを呼び出すButtonをクリック
2. 子ViewがmodalViewで出現
3. 子ViewでUITextFieldに値を入力する。できたら完了ボタンをクリック
5. 子Viewが閉じる
6. 親ViewのUILabelに、子Viewで入力した値が表示されている。

以上の流れを実装していきます。

用意するものは以下のファイルです。

親
 ParentViewController.h
 ParentViewController.m
 ParentViewController.xib
子
    ChildViewController.h
 ChildViewController.m
 ChildViewController.xib

親にはUILabelとmodalViewを呼び出すButtonを、子にはUITextFiledとmodalViewを隠し、TextFieldの入力値を渡すButtonをそれぞれ作ります。
(上の説明は表現上わかりやすくしているだけで、実際の仕組みとは概念が異なります)

protocol:ChildViewControllerDelegateの作成

親のParentViewControllerに、modalViewを閉じた時にhogehogeというメソッドを使うように、
ということを伝えるdelegateを作成します。
protocolの名前はChildViewControllerDelegateとします。

ChildViewController.h
//  
//  ChildViewController.h
//

#import <UIKit/UIKit.h>

@protocol ChildViewControllerDelegate;

@interface ChildViewController : UIViewController

@property (nonatomic, assign) id<ChildViewControllerDelegate> delegate;
@property (weak, nonatomic) IBOutlet UITextField *modalviewText;

@end

@protocol ChildViewControllerDelegate <NSObject>
//protocolで定義するメソッド
-(void)childViewController:(ChildViewController *)childViewController didClose:(NSString *)message;
@end

はじめに、 @protocol ChildViewControllerDelegate; でプロトコルを宣言します。
次に、delegateはプロパティなので、プロパティ宣言をします。

ファイルの一番下で、 @protocol ChildViewControllerDelegate のようにプロトコルの定義をします。(オブジェクトとして振る舞うため、を採用します。)
このプロトコルの中で、ChildViewControllerオブジェクトを閉じるときに使用するメソッドを定義します。

modalViewを隠すボタンを実装

ChildViewController.m
//  
//  ChildViewController.m
//

#import "ChildViewController.h"

@interface ChildViewController ()

@end

@implementation ChildViewController
{
 __unsafe_unretained id<ChildViewControllerDelegate> delegate;
    __weak IBOutlet UITextField *modalviewText; 
}

@synthesize delegate;
@synthesize modalviewText;

- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

//modalViewを隠し、TextFieldの入力値を渡すButton
- (IBAction)touchHideModalView:(id)sender {
    [delegate childViewController:self didClose:modalviewText.text];
}

@end

最近はインスタンス変数をクラスの実装部分に記述することが多いらしいのでそうしました。
イマドキっ子の Objective-Cより)
注意して欲しいのは、 弱参照 にしているところです。強参照にすると循環参照が起きてしまいます。

touchHideModalViewに関しては、ChildViewController:didCloseというメソッドをdelegateで実行する、という処理のみを書きます。modalViewを閉じたりする事は、親の仕事とします。
@synthesizeの指定も忘れずに。

プロトコルのメソッドを使う親の実装

ParentViewController.h
//  
//  ParentViewController.h
//

#import <UIKit/UIKit.h>
#import "ChildViewController.h"

@interface ParentViewController : UIViewController<ChildViewControllerDelegate>

@end

プロトコルを用いる宣言をするために、クラス宣言の後ろに ChildViewControllerDelegate
を記述します。

親のクラスの実装

ParentViewController.m
//  
//  ParentViewController.m
//

#import "ParentViewController.h"
#import "ChildViewController.h"

@interface ParentViewController ()
//modalViewを呼び出すButton
@property (weak, nonatomic) IBOutlet UIButton *modalViewButton;
//UITextFieldの値を表示するラベル
@property (weak, nonatomic) IBOutlet UILabel *viewLabel;

@end

@implementation ParentViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

//modalViewを呼び出すButton
- (IBAction)touchCreateModalView:(id)sender {
    KSGEditImageController *vs =
    [[KSGEditImageController alloc] initWithNibName:@"KSGEditImageController" bundle:nil];
    //delegateにメソッド実行者を自分自身であると伝える
    vc.delegate = self;

    //modal画面の呼び出し
    [self presentViewController:vc animated:YES completion:nil];
}

-(void)childViewController:(ChildViewController *)childViewController didClose:(NSString *)message
{
    _pasteLabel.text = message;
    [self dismissViewControllerAnimated:YES completion:nil];
}

@end

vc.delegate = self; は、delegateに、メソッドを実行するのは自分である、と指定します。
その下の-(void)childViewController:(ChildViewController *)childViewController didClose:(NSString *)messageは、
ChildViewControllerの、touchHideModalViewが実行された時に発火します。

_pasteLabel.text = message でmodalviewTextの値を受け取り、ラベルに代入します。
最後に、dismissViewControllerで子のmodalViewを閉じて、実装完了です。

参考:
ビュー・コントローラ間でのデータの受け渡し、その2「元のページへデータを返す」
[iOS5] ARC : プロパティ属性と使い方

watt1006
mixi
全ての人に心地よいつながりを
http://mixi.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away