目的
- 画面を遷移する
- 前の画面でに入力した値が、次の画面で表示される
- 画面の値を変更せずに元の画面へunwindした場合、前回入力した値が保持されている
次の画面で、値を変更した場合、unwindした場合、変更後の値が元画面に反映されている
前回の画面遷移がベースになります。
今回はパラメータの入力フォームが付き、受け渡しができるようにする部分を説明します
環境
- XCode 8.x
- Objective-C
- MacOS Sierra
ソースはgitHub上へ公開されておりますので、必要に応じてご利用下さい
https://github.com/yukihigasi/objective_c_study_sample
手順
画面
- 画面遷移の方法は前回の内容と同じで、NaivigationViewControllerを利用します
- 今回は二つの画面ViewControllerとSecondViewControllerがあります
- 前画面の入力を、次の遷移先でも表示します
- 逆に先画面で入力に変更した場合、前画面に戻るとその変更がされた状態になります
元画面(ViewController)
- Segueは Forward というidentiferをつけています(任意の名前でOK)
画面には、以下のような画面名を確認する V1 というラベルと
二つの入力項目があり、それぞれ l1v l2v とします
- ソース状ではIBOutletの UITextField型のインスタンスで、以下の変数とひもづきます
ViewController.h
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *l1v;
@property (weak, nonatomic) IBOutlet UITextField *l2v;
@end
先画面(SecondViewController)
- unwindセグエは、RETURNというidentiferをもち
- Actionには前画面のunwindToTopとひもづいています
SecondViewControllerは、
画面名を確認するV2というラベルと
前画面の表示内容をラベルで表示する L1と
ソース状以下のような変数にひもづいています
SecondViewController.h
@interface SecandViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *l1v;
@property (weak, nonatomic) IBOutlet UILabel *l2v;
@property (strong, nonatomic) TransitionObj* transitionObj;
@property (weak, nonatomic) IBOutlet UITextField *f2v;
@end
ソース
- 画面ができたので実装に移ります
元画面(ViewController)
- ヘッダファイルでは、パラメータを保持するTransitionObjectというクラスを保持しています次に解説します
- TransitionObjectは、パラメータの変数をまとめて管理するために用意したもので、iOS上に置いて必須のものではありません、任意でやっています
ViewController.h
#import <UIKit/UIKit.h>
#import "TransitionObj.h"
@interface ViewController : UIViewController
@property (strong, nonatomic) TransitionObj* transitionObj;
@end
- 実装部分は以下のようになります
ViewController.m
#import "ViewController.h"
#import "SecandViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *l1v;
@property (weak, nonatomic) IBOutlet UITextField *l2v;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
if(self.transitionObj){
self.l1v.text=self.transitionObj.l1;
self.l2v.text=self.transitionObj.l2;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"FOWARD"]) {
//ここでパラメータを渡す
self.transitionObj = [[TransitionObj alloc] init];
self.transitionObj.l1 = self.l1v.text;
self.transitionObj.l2 = self.l2v.text;
SecandViewController *dist = segue.destinationViewController;
dist.transitionObj = self.transitionObj;
}
}
- (IBAction)unwindToTop:(UIStoryboardSegue *)segue{
self.l1v.text=self.transitionObj.l1;
self.l2v.text=self.transitionObj.l2;
}
- (IBAction)next:(id)sender {
[self performSegueWithIdentifier:@"FOWARD" sender:self];
}
@end
- まずは次の画面へ値を受けわたすために必要な部分を説明します
- 画面遷移をするときは、遷移直前にprepareForSegue:senderメソッドが呼ばれます
- この中でパラメータの設定など画面遷移の準備をします
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"FOWARD"]) {
//ここでパラメータを渡す
self.transitionObj = [[TransitionObj alloc] init];
self.transitionObj.l1 = self.l1v.text;
self.transitionObj.l2 = self.l2v.text;
SecandViewController *dist = segue.destinationViewController;
dist.transitionObj = self.transitionObj;
}
}
- 最初の if ([segue.identifier isEqualToString:@"FOWARD"]) { は、
- セグエの種類をidentiferで識別して処理を分けています
- 複数の遷移先がある場合、どのsegueでの遷移なのかを識別して画面遷移を準備することができます
今回はFOWARDセグエ当てであるため、上記の中に実装します
次に値をTransitionObjectのプロパティへ受け渡します
ここで、次の画面のオブジェクトを呼び出し、dist変数に保持します
SecandViewController *dist = segue.destinationViewController;
- そうして、受けわたすパラメータの準備ができたら、次の画面へ受け渡します
dist.transitionObj = self.transitionObj;
- 次の画面のプロパティのtransitonObjへ、先ほどパラメータを設定したtransitonObjを受け渡します
- 繰り返しになりますが、TransitionObjectというクラスを作らなくても、直接次の画面の持っている変数へ代入しても問題ありません、一つの変数にまとめるため、任意でこのクラスを用意しています
画面のパラメータを保持する共通クラス(TransitionObject)
- transitionObjectを用意するのは、以下の都合で任意で用意しています
- 画面へ入力された値を保持するため
- 遷移時に受けわたすパラメータを一つにするため
- 実体は、変数があるだけです
TransitonObject.h
#import <Foundation/Foundation.h>
@interface TransitionObj : NSObject
@property (nonatomic) NSString *l1;
@property (nonatomic) NSString *l2;
@property (nonatomic) NSString *l3;
@end
TransitonObject.m
#import "TransitionObj.h"
@implementation TransitionObj
@end
- 本来ですと、ここでは単純に変数が直接定義されてしまっていますが
@property (nonatomic) NSString *l1;
@property (nonatomic) NSString *l2;
@property (nonatomic) NSString *l3;
- 画面ごとに画面の値全てを持つクラスを用意して置いて、クラスをtransitionObjectにもつようにすれば、遷移する全ての画面の値を保持した状態のクラスを作ることができます
- そうすると、画面がどういう形で遷移しても、その画面に入力されていた値をすぐに、シンプルに取り出すことができますし、見通しがよくなリマス
先画面(SecondViewController)
- 画面に表示するラベルと、値を受けわたすtransitionObjが定義されています
- このtransitionObjは先ほどsegue.destinationViewController;で呼び出された画面オブジェクトへ代入したものと同じものです。なので、これには前の画面で入れたパラメータが入っています
SecondViewController.h
#import <UIKit/UIKit.h>
#import "TransitionObj.h"
@interface SecandViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *l1v;
@property (weak, nonatomic) IBOutlet UILabel *l2v;
@property (strong, nonatomic) TransitionObj* transitionObj;
@property (weak, nonatomic) IBOutlet UITextField *f2v;
@end
- 具体的な実装は以下になります
SecondViewController.m
#import <Foundation/Foundation.h>
#import "SecandViewController.h"
#import "TransitionObj.h"
#import "ViewController.h"
@interface SecandViewController ()
@end
@implementation SecandViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.l1v.text=self.transitionObj.l1;
self.l2v.text=self.transitionObj.l2;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"RETURN"]) {
//ここでパラメータを渡す
self.transitionObj.l2 = self.f2v.text;
ViewController *dist = segue.destinationViewController;
dist.transitionObj = self.transitionObj;
}
}
@end
- 画面へ、受け渡されたパラメータを表示します
- 場所は、画面の初期化処理viewDidLoadの中で行います
- (void)viewDidLoad {
[super viewDidLoad];
self.l1v.text=self.transitionObj.l1;
self.l2v.text=self.transitionObj.l2;
}
- 前画面から引き継いだtransitionObjの値を、ラベル等へ設定しています
- これで、前画面のフィールドに入力した値がこの画面で表示されるようになりました
- 数字1と2を入力してForwardボタンを押下します
- V2画面で、先ほどの値が受け渡されています
戻る(unwind)時のパラメータの扱い
- 次は、V2からV1へ戻る時の動きです。この画面では以下のことができます
- Backボタンを押下するとunwindが行われる
- V1はV2への遷移前の値を保持している
unwind時もprepareForSegueが呼ばれます。
今回、unwindセグエのidentiferはRETURNですので、RETURNで識別し遷移前の処理をします
この時も、segue.destinationViewController;で遷移先の画面を取得することができ、その画面へtransitionObjectを受け渡します
SecandViewController.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"RETURN"]) {
//ここでパラメータを渡す
self.transitionObj.l2 = self.f2v.text;
ViewController *dist = segue.destinationViewController;
dist.transitionObj = self.transitionObj;
}
}
- 遷移先で値を受け取ります
- unwindセグエの指定アクションはunwindToTopでしたので、戻り先のアクション名のメソッドが呼び出されます
- ここで画面上のオブジェクトへ値を受け渡します
ViewController.m
- (IBAction)unwindToTop:(UIStoryboardSegue *)segue{
self.l1v.text=self.transitionObj.l1;
self.l2v.text=self.transitionObj.l2;
}
- V2画面で二つ目のラベル(2)を、3と入力してunwindをします
- V1へ戻ると、一つ目のラベルの値が保持されており
- 二つ目のラベルの値が更新されていることが確認できました。
- 以上が、パラメータの受け渡しになります。