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
//
#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
//
#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
//
#import <UIKit/UIKit.h>
#import "ChildViewController.h"
@interface ParentViewController : UIViewController<ChildViewControllerDelegate>
@end
プロトコルを用いる宣言をするために、クラス宣言の後ろに ChildViewControllerDelegate
を記述します。
親のクラスの実装
//
// 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 : プロパティ属性と使い方