web-dev-qa-db-ja.com

Modal View Controllerを終了し、データを戻す

2つのView Controller、firstViewControllersecondViewControllerがあります。このコードを使用して、secondViewControllerに切り替えています(文字列も渡しています)。

secondViewController *second = [[secondViewController alloc] initWithNibName:nil bundle:nil];

second.myString = @"This text is passed from firstViewController!";

second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;

[self presentModalViewController:second animated:YES];

[second release];

次に、secondViewControllerで次のコードを使用して、firstViewControllerに切り替えます。

[self dismissModalViewControllerAnimated:YES];

これらはすべて正常に機能します。私の質問は、データをfirstViewControllerにどのように渡すかです。 secondViewControllerからfirstViewControllerに別の文字列を渡したいです。

84
Andrew Davis

デリゲートプロトコルを使用する必要があります...その方法は次のとおりです。

SecondViewControllerのヘッダーファイルでプロトコルを宣言します。次のようになります。

#import <UIKit/UIKit.h>

@protocol SecondDelegate <NSObject>
-(void)secondViewControllerDismissed:(NSString *)stringForFirst
@end


@interface SecondViewController : UIViewController
{
    id myDelegate;  
}

@property (nonatomic, assign) id<SecondDelegate>    myDelegate;

実装(SecondViewController.m)ファイルでmyDelegateを合成することを忘れないでください:

@synthesize myDelegate;

FirstViewControllerのヘッダーファイルで、次の操作を行ってSecondDelegateプロトコルをサブスクライブします。

#import "SecondViewController.h"

@interface FirstViewController:UIViewController <SecondDelegate>

FirstViewControllerでSecondViewControllerをインスタンス化するとき、次のことを行う必要があります。

// If you're using a view controller built with Interface Builder.
SecondViewController *second = [[SecondViewController alloc] initWithNibName:"SecondViewController" bundle:[NSBundle mainBundle]];
// If you're using a view controller built programmatically.
SecondViewController *second = [SecondViewController new]; // Convenience initializer that uses alloc] init]
second.myString = @"This text is passed from firstViewController!";
second.myDelegate = self;
second.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:second animated:YES];
[second release];

最後に、最初のView Controllerの実装ファイル(FirstViewController.m)で、secondViewControllerDismissedのSecondDelegateのメソッドを実装します。

- (void)secondViewControllerDismissed:(NSString *)stringForFirst
{
    NSString *thisIsTheDesiredString = stringForFirst; //And there you have it.....
}

次に、2番目のView Controllerを閉じようとしているときに、最初のView Controllerに実装されているメソッドを呼び出します。この部分は簡単です。 2番目のView Controllerで、終了コードの前にコードを追加するだけです。

if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:)])
{
    [self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!"];
}
[self dismissModalViewControllerAnimated:YES];

デリゲートプロトコルは非常に、非常に、非常に便利です。それらに慣れることは良いことです:)

NSNotificationsはこれを行う別の方法ですが、ベストプラクティスとして、複数のviewControllerまたはオブジェクト間で通信する場合に使用することをお勧めします。 NSNotificationsの使用に興味がある場合は、以前に投稿した回答を次に示します。 appdelegate のスレッドから複数のViewControllerにイベントを送信する

編集:

複数の引数を渡したい場合、閉じる前のコードは次のようになります。

if([self.myDelegate respondsToSelector:@selector(secondViewControllerDismissed:argument2:argument3:)])
{
    [self.myDelegate secondViewControllerDismissed:@"THIS IS THE STRING TO SEND!!!" argument2:someObject argument3:anotherObject];
}
[self dismissModalViewControllerAnimated:YES];

つまり、firstViewController内のSecondDelegateメソッドの実装は次のようになります。

- (void) secondViewControllerDismissed:(NSString*)stringForFirst argument2:(NSObject*)inObject1 argument3:(NSObject*)inObject2
{
    NSString thisIsTheDesiredString = stringForFirst;
    NSObject desiredObject1 = inObject1;
    //....and so on
}
142
Sid

私はここで場違いになるかもしれませんが、私は非常に冗長なデリゲート/プロトコルアプローチよりもブロック構文を好むようになり始めています。 vc1からvc2を作成する場合は、vc2にブロックであるvc1から設定できるプロパティがあります!

@property (nonatomic, copy) void (^somethingHappenedInVC2)(NSString *response);

次に、vc1に伝えたいことがvc2で発生した場合、vc1で定義したブロックを実行するだけです!

self.somethingHappenedInVC2(@"Hello!");

これにより、vc2からvc1にデータを送り返すことができます。魔法のように。 IMO、これはプロトコルよりもはるかに簡単/クリーンです。ブロックは素晴らしく、可能な限り受け入れる必要があります。

編集-改善された例

ユーザーから入力を取得するために一時的にmodalVCを表示するmainVCがあるとします。 mainVCからそのmodalVCを提示するには、mainVC内でalloc/initする必要があります。かなり基本的なもの。このmodalVCオブジェクトを作成するときに、両方のvcオブジェクト間で簡単に通信できるようにするブロックプロパティを設定することもできます。上記の例を使用して、次のプロパティをmodalVCの.hファイルに入れてみましょう。

 @property (nonatomic, copy) void (^somethingHappenedInModalVC)(NSString *response);  

次に、mainVCで、新しいmodalVCオブジェクトをalloc/init'dした後、次のようにmodalVCのブロックプロパティを設定します。

ModalVC *modalVC = [[ModalVC alloc] init];
modalVC.somethingHappenedInModalVC = ^(NSString *response) {
     NSLog(@"Something was selected in the modalVC, and this is what it was:%@", response);
}

したがって、ブロックプロパティを設定し、そのブロックが実行されたときに何が起こるかを定義しています。

最後に、私たちのmodalVCには、文字列のdataSource配列によって支えられたtableViewControllerがあります。行を選択したら、次のようなことができます。

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
      NSString *selectedString = self.dataSource[indexPath.row];
      self.somethingHappenedInModalVC(selectedString);
 }

そしてもちろん、modalVCで行を選択するたびに、mainVCのNSLog行からコンソール出力を取得します。お役に立てば幸いです!

40
Lizza

うーん、通知センターを探して、通知で情報を返します。 ここではリンゴがそれを引き受けています -誰かが他の提案がない限り、私は個人的にこのアプローチを取ります

4
theiOSDude

2番目のView Controllerでデリゲートプロトコルを定義し、最初の1つを2番目のデリゲートにします。

2
cschwarz