web-dev-qa-db-ja.com

ビューコントローラ間のデータ受け渡し

私はiOSとObjective-C、そしてMVC全体のパラダイムに不慣れです。

データ入力フォームとして機能するビューがあり、ユーザーに複数の製品を選択するオプションを与えたいと思います。製品はUITableViewControllerで別のビューに表示されており、複数選択が可能になっています。

私の質問は、あるビューから別のビューにデータを転送する方法を教えてください。 UITableViewの選択を配列で保持しますが、フォームの送信時に他のデータと一緒にCore Dataに保存できるようにするにはどうすればよいでしょうか。

私は周りをサーフィンして、何人かの人々がアプリデリゲートで配列を宣言するのを見ました。私はシングルトンについて何かを読みましたが、それらが何であるかを理解していません、そして私はデータモデルを作成することについて何かを読みます。

これを実行するための正しい方法は何でしょうか。また、どうすればよいでしょうか。

1254
Matt Price

この質問はここではstackoverflowで非常に人気があるように思われるので、私は私のようにiOSの世界から始める人々を助けるために私はもっと良い答えを出すことを試みると思いました。

私はこの答えが人々に理解されるのに十分明確であり、私が何も見逃していないことを願っています。

データを転送する

別のView ControllerからView Controllerにデータを渡す。ナビゲーションスタックにプッシュしている可能性があるオブジェクト/値をあるView Controllerから別のView Controllerに渡す場合は、このメソッドを使用します。

この例では、ViewControllerAViewControllerBがあります。

BOOLからViewControllerAViewControllerB値を渡すためには、次のようにします。

  1. ViewControllerB.hBOOLのプロパティを作成します

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. ViewControllerAではViewControllerBについて説明する必要があるので、 

    #import "ViewControllerB.h"
    

    それからビューをロードしたい場所。 didSelectRowAtIndexまたはIBActionは、navスタックにプッシュする前にViewControllerBにプロパティを設定する必要があります。

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.isSomethingEnabled = YES;
    [self pushViewController:viewControllerB animated:YES];
    

    これはisSomethingEnabledViewControllerBBOOLの値YESに設定します。

Seguesを使用してデータを転送する

ストーリーボードを使用している場合は、セグエを使用している可能性が最も高いので、データを転送するにはこの手順が必要になります。これは上記と似ていますが、View Controllerをプッシュする前にデータを渡す代わりに、というメソッドを使用します。

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

BOOLからViewControllerAViewControllerBを渡すには、次のようにします。

  1. ViewControllerB.hBOOLのプロパティを作成します

    @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. ViewControllerAではViewControllerBについて説明する必要があるので、

    #import "ViewControllerB.h"
    
  3. ストーリーボード上でViewControllerAからViewControllerBへのセグエを作成し、それに識別子を付けます。この例では"showDetailSegue"と呼びます。

  4. 次に、任意のセグエが実行されたときに呼び出されるメソッドをViewControllerAに追加する必要があります。そのため、どのセグエが呼び出されたのかを検出してから何かを実行する必要があります。この例では"showDetailSegue"をチェックし、それが実行された場合はBOOLの値をViewControllerBに渡します。

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            ViewControllerB *controller = (ViewControllerB *)segue.destinationViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    ビューをナビゲーションコントローラに埋め込む場合は、上記の方法を次のように少し変更する必要があります。

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
        if([segue.identifier isEqualToString:@"showDetailSegue"]){
            UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
            ViewControllerB *controller = (ViewControllerB *)navController.topViewController;
            controller.isSomethingEnabled = YES;
        }
    }
    

    これはisSomethingEnabledViewControllerBBOOLの値YESに設定します。

データの受け渡し

データをViewControllerBからViewControllerAに戻すには、Protocols and DelegatesまたはBlocks)を使う必要があります。後者は、コールバックの疎結合メカニズムとして使用できます。

これを行うには、ViewControllerAViewControllerBのデリゲートにします。これによりViewControllerBViewControllerAにメッセージを送り返し、データを送り返すことができます。

ViewControllerAViewControllerBのデリゲートにするには、ViewControllerBのプロトコルに準拠する必要があります。これはどのメソッドを実装しなければならないかをViewControllerAに伝えます。

  1. ViewControllerB.hでは、#importの下、@interfaceの上にはプロトコルを指定します。

    @class ViewControllerB;
    
    @protocol ViewControllerBDelegate <NSObject>
    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item;
    @end
    
  2. 次にまだViewControllerB.hdelegateプロパティを設定してViewControllerB.mに合成する必要があります

    @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  3. ViewControllerBでは、View Controllerを開くときにdelegate上のメッセージを呼び出します。

    NSString *itemToPassBack = @"Pass this value back to ViewControllerA";
    [self.delegate addItemViewController:self didFinishEnteringItem:itemToPassBack];
    
  4. ViewControllerBについては以上です。 ViewControllerA.hでは、ViewControllerAViewControllerBをインポートし、そのプロトコルに準拠するように指示します。

    #import "ViewControllerB.h"
    
    @interface ViewControllerA : UIViewController <ViewControllerBDelegate>
    
  5. ViewControllerA.mでは、私たちのプロトコルから以下のメソッドを実装してください。

    - (void)addItemViewController:(ViewControllerB *)controller didFinishEnteringItem:(NSString *)item
    {
        NSLog(@"This was returned from ViewControllerB %@",item);
    }
    
  6. viewControllerBをナビゲーションスタックにプッシュする前に、ViewControllerBがそのデリゲートであることをViewControllerAに伝える必要があります。そうしないとエラーが発生します。

    ViewControllerB *viewControllerB = [[ViewControllerB alloc] initWithNib:@"ViewControllerB" bundle:nil];
    viewControllerB.delegate = self
    [[self navigationController] pushViewController:viewControllerB animated:YES];
    

参考文献

  1. デリゲーションを使用して他のView Controllerと通信する _ 『View Controllerプログラミングガイド』
  2. デリゲートパターン

NS通知センター データを渡す別の方法です。 

// add observer in controller(s) where you want to receive data
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeepLinking:) name:@"handleDeepLinking" object:nil];

-(void) handleDeepLinking:(NSNotification *) notification {
    id someObject = notification.object // some custom object that was passed with notification fire.
}

// post notification
id someObject;
[NSNotificationCenter.defaultCenter postNotificationName:@"handleDeepLinking" object:someObject];

あるクラスから別のクラスにデータを渡す (クラスには、任意のコントローラ、ネットワーク/セッションマネージャ、UIViewサブクラス、またはその他のクラスを指定できます)

ブロックは無名関数です。

この例では、 Controller B から Controller A にデータを渡します。

ブロックを定義します

@property void(^selectedVoucherBlock)(NSString *); // in ContollerA.h

ブロックハンドラ(リスナ)の追加 値が必要な場所(たとえば、ControllerAでAPI応答が必要、またはAでContorllerBデータが必要)

// in ContollerA.m

- (void)viewDidLoad {
    [super viewDidLoad];
    __unsafe_unretained typeof(self) weakSelf = self;
    self.selectedVoucherBlock = ^(NSString *voucher) {
        weakSelf->someLabel.text = voucher;
    };
}

コントローラBに行く

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
ControllerB *vc = [storyboard instantiateViewControllerWithIdentifier:@"ControllerB"];
vc.sourceVC = self;
    [self.navigationController pushViewController:vc animated:NO];

ファイアブロック

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: 
(NSIndexPath *)indexPath {
    NSString *voucher = vouchersArray[indexPath.row];
    if (sourceVC.selectVoucherBlock) {
        sourceVC.selectVoucherBlock(voucher);
    }
    [self.navigationController popToViewController:sourceVC animated:YES];
}

ブロックのもう一つの例

1599
Matt Price

迅速

ここやStackOverflowの周りにはたくさんの説明がありますが、基本的なものを使いこなそうとしているだけの初心者であれば、このYouTubeチュートリアルを見てみてください(それがやっと使い方を理解するのに役立ちました)。

次のView Controllerにデータを渡す

以下はビデオに基づいた例です。これは、First View ControllerのテキストフィールドからSecond View Controllerのラベルに文字列を渡すことです。

enter image description here

Interface Builderでストーリーボードレイアウトを作成します。セグエを作るために、あなただけ Control ボタンをクリックしてSecond View Controllerまでドラッグします。

First View Controller

First View Controllerのコードは

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // get a reference to the second view controller
        let secondViewController = segue.destination as! SecondViewController

        // set a variable in the second view controller with the String to pass
        secondViewController.receivedString = textField.text!
    }

}

セカンドビューコントローラー

Second View Controllerのコードは

import UIKit

class SecondViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    // This variable will hold the data being passed from the First View Controller
    var receivedString = ""

    override func viewDidLoad() {
        super.viewDidLoad()

        // Used the text from the First View Controller to set the label
        label.text = receivedString
    }

}

忘れないでください

  • UITextFieldUILabelのアウトレットを接続します。
  • 1番目と2番目のView ControllerをIBの適切なSwiftファイルに設定します。

前のView Controllerにデータを戻す

2番目のView Controllerから最初のView Controllerにデータを戻すには、 プロトコルとデリゲート を使用します。このビデオは、そのプロセスについては非常に明確な説明です。

以下は、ビデオを基にした例です(いくつか変更を加えています)。

enter image description here

Interface Builderでストーリーボードレイアウトを作成します。また、セグエを作るために、あなただけ Control ボタンからSecond View Controllerにドラッグします。セグエ識別子をshowSecondViewControllerに設定します。また、次のコードの名前を使用してアウトレットとアクションを接続することを忘れないでください。

First View Controller

First View Controllerのコードは

import UIKit

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destination as! SecondViewController
            secondViewController.delegate = self
        }
    }

    func userDidEnterInformation(info: String) {
        label.text = info
    }
}

私たちのカスタムDataEnteredDelegateプロトコルの使用に注意してください。

セカンドビューコントローラとプロトコル

2番目のView Controllerのコードは

import UIKit

// protocol used for sending data back
protocol DataEnteredDelegate: class {
    func userDidEnterInformation(info: String)
}

class SecondViewController: UIViewController {

    // making this a weak variable so that it won't create a strong reference cycle
    weak var delegate: DataEnteredDelegate? = nil

    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {

        // call this method on whichever class implements our delegate protocol
        delegate?.userDidEnterInformation(info: textField.text!)

        // go back to the previous view controller
        _ = self.navigationController?.popViewController(animated: true)
    }
}

protocolは、View Controllerクラスの外部にあります。

それでおしまい。今すぐアプリを実行すると、2番目のView Controllerから最初のView Controllerへデータを送り返すことができるはずです。

164
Suragch

MVCのMは "Model"のためのものであり、MVCパラダイムでのモデルクラスの役割はプログラムのデータを管理することです。モデルはビューの反対です。ビューはデータの表示方法を認識していますが、データの処理方法については何も認識していません。一方、モデルはデータの処理方法についてはすべて認識しています。モデルは複雑になる可能性がありますが、必ずしもそうである必要はありません。アプリのモデルは、文字列や辞書の配列のように単純なものでもかまいません。

コントローラーの役割は、ビューとモデルを仲介することです。そのため、1つ以上のビューオブジェクトと1つ以上のモデルオブジェクトへの参照が必要です。モデルが辞書の配列で、各辞書がテーブルの1行を表すとしましょう。アプリのルートビューにはそのテーブルが表示され、ファイルから配列をロードすることに責任があるかもしれません。ユーザがテーブルに新しい行を追加することにしたとき、彼らはいくつかのボタンをタップします、そして、あなたのコントローラは新しい(可変の)辞書を作成してそれを配列に追加します。行を埋めるために、コントローラは詳細ビューコントローラを作成し、それに新しいディクショナリを渡します。詳細ビューコントローラは辞書を埋めて戻ります。辞書はすでにモデルの一部なので、他に何もする必要はありません。

122
Caleb

IOSの異なるクラスにデータを受信する方法はいくつかあります。例えば ​​- 

  1. 別のクラスの割り当て後に直接初期化します。
  2. 委任 - データを戻す 
  3. 通知 - 一度に複数のクラスにデータをブロードキャストするためのものです。
  4. NSUserDefaultsに保存 - 後でアクセスするため
  5. シングルトンクラス 
  6. データベースやその他のplistなどの保存メカニズム.

しかし、現在のクラスで割り当てが行われている別のクラスに値を渡すという単純なシナリオでは、最も一般的で好ましい方法は、割り当て後に値を直接設定することです。これは次のように行われます: -

2つのコントローラーを使ってそれを理解することができます - Controller1とController2  

Controller1クラスでController2オブジェクトを作成し、渡されたString値でそれをプッシュするとします。これはこのようにすることができます: -

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj passValue:@"String"];
    [self pushViewController:obj animated:YES];
}

Controller2クラスの実装では、この関数は次のようになります。 

@interface Controller2  : NSObject

@property (nonatomic , strong) NSString* stringPassed;

@end

@implementation Controller2

@synthesize stringPassed = _stringPassed;

- (void) passValue:(NSString *)value {

    _stringPassed = value; //or self.stringPassed = value
}

@end

これと同じ方法で、Controller2クラスのプロパティを直接設定することもできます。

- (void)pushToController2 {

    Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
    [obj setStringPassed:@"String"];  
    [self pushViewController:obj animated:YES];
}

複数の値を渡すには、次のように複数のパラメータを使用できます -

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passValue:@“String1” andValues:objArray withDate:date]; 

また、共通の機能に関連する3つ以上のパラメータを渡す必要がある場合は、値をModelクラスに格納し、そのmodelObjectを次のクラスに渡すことができます。

ModelClass *modelObject = [[ModelClass alloc] init]; 
modelObject.property1 = _property1;
modelObject.property2 = _property2;
modelObject.property3 = _property3;

Controller2 *obj = [[Controller2 alloc] initWithNib:@"Controller2" bundle:nil];
[obj passmodel: modelObject];

あなたがしたいのであれば短いので -

1) set the private variables of the second class initialise the values by calling a custom function and passing the values.
2) setProperties do it by directlyInitialising it using the setter method.
3) pass more that 3-4 values related to each other in some manner , then create a model class and set values to its object and pass the object using any of the above process.

お役に立てれば

87
borncrazy

さらに調査した結果、Protocols and Delegatesがこれを実行するための正しい方法であることがわかった。

私はこの例を使いました

View Controllerと他のオブジェクトとの間でデータを共有する @ iPhone Dev SDK

うまくいき、ビュー間で文字列と配列を前後に渡すことができました。

ご協力ありがとうございます

78
Matt Price

ブロックを渡すことで、最もシンプルで洗練されたバージョンを見つけることができます。返されたデータを "A"として、返されるView Controllerを "B"として名前を付けます。この例では、2つの値を取得します。1つはType1、2つ目はType2です。

Storyboardを使用すると仮定すると、最初のコントローラは、たとえばセグエ準備中にコールバックブロックを設定します。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController isKindOfClass:[BViewController class]])
    {
        BViewController *viewController = segue.destinationViewController;

        viewController.callback = ^(Type1 *value1, Type2 *value2) {
            // optionally, close B
            //[self.navigationController popViewControllerAnimated:YES];

            // let's do some action after with returned values
            action1(value1);
            action2(value2);
        };

    }
}

そして "B"ビューコントローラはコールバックプロパティ、BViewController.hを宣言する必要があります。

// it is important to use "copy"
@property (copy) void(^callback)(Type1 *value1, Type2 *value2);

実装ファイルBViewController.mよりも、コールバックを返すために必要な値を取得した後で呼び出す必要があります。

if (self.callback)
    self.callback(value1, value2);

覚えておくべき1つのことは、ブロックを使うことはしばしば説明された here のように強くて弱い参照を管理する必要があるということです。

61
Leszek Zarna

与えられた答えの多くにいくつかの良い情報がありますが、どれも質問に完全に対処しません。

質問は、View Controller間での情報の受け渡しについて尋ねています。具体的な例では、ビュー間で情報を受け渡しすることについて説明していますが、iOSには自明の新しさがあり、元のポスターはビュー間ではなくViewControllers間を意味していました(ViewControllerの関与なし)。すべての答えが2つのView Controllerに焦点を合わせているように見えますが、情報交換に2つ以上のView Controllerを含める必要があるようにアプリが進化した場合はどうなりますか? 

元のポスターはまた シングルトン AppDelegate の使用について尋ねました。これらの質問は答えられる必要があります。

完全な答えを望んでいるこの質問を見ている他の誰かを助けるために、私はそれを提供しようとするつもりです。

アプリケーションシナリオ

非常に仮説的で抽象的な議論をするのではなく、それは具体的なアプリケーションを念頭に置いておくのに役立ちます。 2ビューコントローラの状況と2ビューコントローラ以上の状況を定義するために、2つの具体的なアプリケーションシナリオを定義します。

シナリオ1: 最大で2つのView Controllerが情報を共有する必要があります。図1を参照してください。 

diagram of original problem

アプリケーションには2つのView Controllerがあります。 ViewControllerA(データ入力フォーム)とView Controller B(製品リスト)があります。商品リストで選択されている項目は、データ入力フォームのテキストボックスに表示されている項目と一致する必要があります。このシナリオでは、ViewControllerAとViewControllerBは互いに直接通信する必要があり、他のView Controllerとは通信しません。 

シナリオ2 :3人以上のView Controllerが同じ情報を共有する必要があります図2を参照してください。

home inventory application diagram

アプリケーションには4つのView Controllerがあります。家の在庫を管理するためのタブベースのアプリケーションです。 3つのView Controllerは、同じデータに対して異なる方法でフィルタ処理されたビューを表示します。

  • ViewControllerA - 高級アイテム 
  • ViewControllerB - 保険をかけられていない品目
  • ViewControllerC - 家の在庫全体 
  • ViewControllerD - 新しい商品フォームを追加する

個々の項目が作成または編集されたときはいつでも、他のView Controllerとも同期する必要があります。たとえば、ViewControllerDにボートを追加してもまだ保険に入っていない場合は、ユーザーがViewControllerA(高級品)およびViewControllerC(ホーム在庫全体)に移動したときにボートが表示される必要があります。 ViewControllerB(非保険商品)。新しい項目を追加するだけでなく、項目を削除したり(4つのView Controllerのいずれかから許可されている場合があります)、既存の項目を編集したりすることもできます。編集用).

すべてのView Controllerが同じデータを共有する必要があるため、4つすべてのView Controllerが同期している必要があります。したがって、1つのView Controllerが基本データを変更するたびに、他のすべてのView Controllerと何らかの通信を行う必要があります。このシナリオでは、各View Controllerが他のView Controllerと直接通信することを望まないことは明らかです。はっきりしない場合は、(4つではなく)20個の異なるView Controllerがあるかどうかを検討してください。 1台のView Controllerが変更されたときに、他の19台のView Controllerそれぞれに通知するのは、どれほど困難でエラーが発生しやすいでしょうか。

解決策:デリゲートとオブザーバパターン、そしてシングルトン

シナリオ1では、他の答えが示したように、いくつかの実行可能な解決策があります。

  • セグエス
  • 代表者
  • view Controllerに直接プロパティを設定する
  • NSUserDefaults(実際には不適切な選択)

シナリオ2では、他に実行可能な解決策があります。

  • 観察者パターン 
  • シングルトン

シングルトン はクラスのインスタンスであり、そのインスタンスはその存続期間中に存在する唯一のインスタンスです。シングルトンは、それが単一のインスタンスであるという事実からその名前を取得します。通常シングルトンを使用する開発者はそれらにアクセスするための特別なクラスメソッドを持っています。 

+ (HouseholdInventoryManager*) sharedManager; {
    static dispatch_once_t onceQueue;
    static HouseholdInventoryManager* _sharedInstance;

    // dispatch_once is guaranteed to only be executed once in the
    // lifetime of the application
    dispatch_once(&onceQueue, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}

シングルトンとは何かを理解したので、シングルトンがどのようにオブザーバパターンに収まるかを説明しましょう。オブザーバパターンは、あるオブジェクトが別のオブジェクトによる変更に応答するために使用されます。 2番目のシナリオでは、4つの異なるView Controllerがあり、それらすべてが基礎となるデータへの変更について知りたいと考えています。 「基礎となるデータ」は単一のインスタンス、シングルトンに属する必要があります。 「変化について知る」ことは、シングルトンに加えられた変化を観察することによって達成される。

家の在庫アプリケーションは在庫品目のリストを管理するように設計されているクラスの単一のインスタンスを持つでしょう。管理者は、世帯品目の集まりを管理します。以下はデータマネージャのクラス定義です。

#import <Foundation/Foundation.h>

@class JGCHouseholdInventoryItem;

@interface HouseholdInventoryManager : NSObject
/*!
 The global singleton for accessing application data
 */
+ (HouseholdInventoryManager*) sharedManager;


- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;

- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end

ホームインベントリアイテムのコレクションが変更されたら、View Controllerにこの変更を知らせる必要があります。上記のクラス定義は、これがどのように発生するのかを明確にしていません。観察者パターンに従う必要があります。 View ControllerはsharedManagerを正式に監視する必要があります。他のオブジェクトを観察する方法は2つあります。

  • キー値監視(KVO)
  • NSNotificationCenter。

シナリオ2では、KVOを使用して観察できるHouseholdInventoryManagerの単一プロパティはありません。簡単に観察できる単一のプロパティがないため、この場合はオブザーバパターンをNSNotificationCenterを使用して実装する必要があります。 4つのView Controllerはそれぞれ通知を購読し、sharedManagerは必要に応じて通知センターに通知を送信します。在庫マネージャは、在庫アイテムのコレクションがいつ変更されるかを知ることに関心がある可能性がある、View Controllerまたは他のクラスのインスタンスについて何も知る必要はありません。 NSNotificationCenterはこれらの実装の詳細を引き受けます。ビューコントローラは単に通知を購読し、データマネージャは単に通知を投稿します。

多くの初心者プログラマは、アプリケーションの有効期間中に常に1つの Application Delegate が存在するという事実を利用します。初心者プログラマーは、アプリケーション内の他の場所からアクセスするための便利さとして、この事実を使ってオブジェクトと機能をappDelegateに詰め込みます。 AppDelegateがシングルトンであるという理由だけで、他のすべてのシングルトンを置き換える必要があるという意味ではありません。 1つのクラスに負担がかかり過ぎるため、これは不適切な方法です。オブジェクト指向の良い方法では実行できません。各クラスには、簡単に説明できる明確な役割があります。多くの場合、クラスの名前だけです。

Application Delegateが肥大化し始めたときはいつでも、機能をシングルトンに削除し始めます。たとえば、コアデータスタックはAppDelegateに残すべきではなく、代わりに独自のクラスであるcoreDataManagerクラスに入れるべきです。 

参考文献

50
Jason Cross

ViewController 2(destination)からviewController 1(Source)にデータを戻すことは、もっとおもしろいことです。 :

  • 委任 
  • お知らせ
  • ユーザーデフォルト
  • シングルトン

それらについてはすでに説明しました。

私はもっ​​とたくさんの方法があることがわかりました:

-Using Blockコールバック:

vC1のprepareForSegueメソッドでそれを使う

NextViewController *destinationVC = (NextViewController *) segue.destinationViewController;
[destinationVC setDidFinishUsingBlockCallback:^(NextViewController *destinationVC)
{
    self.blockLabel.text = destination.blockTextField.text;
}];

- ストーリーボードの使用アンワインド(終了)

次のように、VC 1にUIStoryboardSegue引数を持つメソッドを実装します。

-(IBAction)UnWindDone:(UIStoryboardSegue *)segue { }

StoryBoardの中で、「戻る」ボタンをvcの緑の終了ボタン(アンワインド)にフックします。 ] VC2のprepareForSegue内のdestinationViewControllerプロパティおよび VC1のプロパティを元に戻す前に変更します。

  • ストーリーボードを使用する別のオプション巻き戻し(終了) - あなたはVC1で書いた方法を使うことができます

    -(IBAction)UnWindDone:(UIStoryboardSegue *)segue {
        NextViewController *nextViewController = segue.sourceViewController;
        self.unwindLabel.text = nextViewController.unwindPropertyPass;
    } 
    

    そしてVC1のprepareForSegueでは、共有したい任意のプロパティを変更できます。

どちらのアンワインドオプションでも、ボタンのtagプロパティを設定し、prepareForSegueのでチェックすることができます。 

私が議論に何かを追加したことを願っています。 

:)乾杯。

38
Yevgeni

データを共有する方法は複数あります。

  1. NSUserDefaultsを使っていつでもデータを共有できます。選択したキーに関して共有する値を設定し、次のView Controllerでそのキーに関連付けられたNSUserDefaultから値を取得します。 

    [[NSUserDefaults standardUserDefaults] setValue:value forKey:key]
    [[NSUserDefaults standardUserDefaults] objectForKey:key]
    
  2. viewcontrollerAにプロパティを作成するだけです。 viewcontrollerA内にviewcontrollerBのオブジェクトを作成し、そのプロパティに目的の値を割り当てます。

  3. このためにカスタムデリゲートを作成することもできます。

37
Anubrata Santra

OPはView Controllerについて言及していませんでしたが、答えの多くはそうしているので、あるView Controllerから別のView Controllerへデータを渡したいときにLLVMの新機能のいくつかがこれを容易にしたのです。いくつかの結果を取り戻します。

ストーリーボードセグ、ARCとLLVMブロックはこれを私にとってこれまで以上に簡単にします。上記のいくつかの答えはすでにストーリーボードとセグエスを述べていますが、それでも代表団に頼っていました。デリゲートを定義することは確かにうまくいきますが、ポインターやコードブロックを渡す方が簡単なことがあるかもしれません。

UINavigatorとセグエでは、サブサービスコントローラーに情報を渡して情報を取り戻す簡単な方法があります。 ARCは、NSObjectsから派生したものへのポインタの受け渡しを簡単にするので、サブサービスコントローラにデータの追加/変更/変更を行わせる場合は、可変インスタンスへのポインタを渡します。ブロックを使用するとアクションの受け渡しが簡単になるため、サブサービスコントローラーに上位コントローラーのアクションを呼び出させたい場合は、ブロックに渡します。あなたにとって意味のある引数をいくつでも受け入れるようにブロックを定義します。また、複数のブロックを使用するようにAPIを設計することもできます。

ここにセグエのりの2つの些細な例があります。 1つ目は入力用に渡された1つのパラメーター、もう1つは出力用に渡されたパラメーターを示しています。

// Prepare the destination view controller by passing it the input we want it to work on
// and the results we will look at when the user has navigated back to this controller's view.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results
     // by virtue of both controllers having a pointer to the same object.
     andResults:self.resultsFromNextController];
}

この2番目の例は、2番目の引数にコールバックブロックを渡すことを示しています。私はブロックを使うのが好きです。なぜならそれは関連する細部をソース - より高いレベルのソース - の近くに密接に保つからです。

// Prepare the destination view controller by passing it the input we want it to work on
// and the callback when it has done its work.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    [[segue destinationViewController]

     // This parameter gives the next controller the data it works on.
     segueHandoffWithInput:self.dataForNextController

     // This parameter allows the next controller to pass back results.
     resultsBlock:^(id results) {
         // This callback could be as involved as you like.
         // It can use Grand Central Dispatch to have work done on another thread for example.
        [self setResultsFromNextController:results];
    }];
}
36
WeakPointer

あるコントローラから別のコントローラにデータを渡したい場合は、このコードを試してください。

FirstViewController.h

@property (nonatomic, retain) NSString *str;

SecondViewController.h

@property (nonatomic, retain) NSString *str1;

FirstViewController.m

- (void)viewDidLoad
   {
     // message for the second SecondViewController
     self.str = @"text message";

     [super viewDidLoad];
   }

-(IBAction)ButtonClicked
 {
   SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
   secondViewController.str1 = str;
  [self.navigationController pushViewController:secondViewController animated:YES];
 }
27
user2998756

私は長い間この解決策を探していました、私はそれを見つけました。まず、SecondViewController.hファイル内のすべてのオブジェクトを次のように宣言します。

@interface SecondViewController: UIviewController 
{
    NSMutableArray *myAray;
    CustomObject *object;
}

今すぐあなたの実装ファイルでこのようにそれらのオブジェクトのためにメモリを割り当てます

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
     if (self) 
     {
         // Custom initialization
         myAray=[[NSMutableArray alloc] init];
         object=[[CustomObject alloc] init];
     }
     return self;
}

これでArrayとobjectにメモリを割り当てました。これで、このViewControllerをプッシュする前に、そのメモリをいっぱいにすることができます

SecondViewController.hに行き、2つのメソッドを書きます。

-(void)setMyArray:(NSArray *)_myArray;
-(void)setMyObject:(CustomObject *)_myObject;

実装ファイルでは、関数を実装することができます 

-(void)setMyArray:(NSArray *)_myArray
{
     [myArra addObjectsFromArray:_myArray];
}
-(void)setMyObject:(CustomObject *)_myObject
{
     [object setCustomObject:_myObject];
}

あなたのCustomObjectがそれにセッター関数を持たなければならないことを期待しています。

これで基本的な作業は完了です。あなたがSecondViewControllerをプッシュしたい場所に行き、以下のことをする

SecondViewController *secondView= [[SecondViewController alloc] initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]] ;
[secondView setMyArray:ArrayToPass];
[secondView setMyObject:objectToPass];
[self.navigationController pushViewController:secondView animated:YES ];

スペルミスには注意してください。 

25
AsifHabib

これはそれを行う方法ではありません、あなたはデリゲートを使用するべきです、私は2つのView Controller ViewController1とViewController2があり、このチェックは最初のものにあると仮定します適切な方法でそれを達成するには、以下を実行する必要があります。

プロジェクトに新しいファイルを追加する(Objective-Cプロトコル)File - > New。今度はそれをViewController1Delegateまたはあなたが望むものに名前を付けて@interfaceと@endディレクティブの間にそれらを書く

@optional

- (void)checkStateDidChange:(BOOL)checked;

今ViewController2.hに行き、追加します

#import "ViewController1Delegate.h"

次にその定義を

@interface ViewController2: UIViewController<ViewController1Delegate>

それではViewController2.mに行き、実装の中に以下を追加してください。

- (void)checkStateDidChange:(BOOL)checked {
     if (checked) {
           // Do whatever you want here
           NSLog(@"Checked");
     }
     else {
           // Also do whatever you want here
           NSLog(@"Not checked");
     }
}

ViewController1.hに移動して、次のプロパティを追加します。

@property (weak, nonatomic) id<ViewController1Delegate> delegate; 

何らかのイベントの後にViewController2内にViewController1を作成している場合は、NIBファイルを使用して次のようにしてください。

ViewController1* controller = [[NSBundle mainBundle] loadNibNamed:@"ViewController1" owner:self options:nil][0];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];

ViewController1で変更されたチェックのイベントが検出されたときはいつでも、あなたはすべて設定済みです。

[delegate checkStateDidChange:checked]; // You pass here YES or NO based on the check state of your control

私があなたの質問をきちんと理解していなかったならば、はっきりしない何かがあるならば私に言いなさい。

21
Boda Taljo

あるビューコントローラから別のビューコントローラにデータを送信したい場合は、次のようにします。

ViewController:viewControllerAとviewControllerBがあるとします。

今viewControllerB.hに

@interface viewControllerB : UIViewController {

  NSString *string;
  NSArray *array;

}

- (id)initWithArray:(NSArray)a andString:(NSString)s;

ViewControllerB.m内

#import "viewControllerB.h"

@implementation viewControllerB

- (id)initWithArray:(NSArray)a andString:(NSString)s {

   array = [[NSArray alloc] init];
   array = a;

   string = [[NSString alloc] init];
   string = s;

}

ViewControllerA.m内 

#import "viewControllerA.h"
#import "viewControllerB.h"

@implementation viewControllerA

- (void)someMethod {

  someArray = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];
  someString = [NSString stringWithFormat:@"Hahahahaha"];

  viewControllerB *vc = [[viewControllerB alloc] initWithArray:someArray andString:someString];

  [self.navigationController pushViewController:vc animated:YES];
  [vc release];

}

これがデリゲートを設定せずにviewControllerAからviewControllerBにデータを渡す方法です。 ;)

19
Aniruddh Joshi

私の場合、アプリ内のほぼどこからでもデータにアクセスできるグローバルオブジェクトとして機能できるシングルトンクラスを使用しました。まず、シングルトンクラスを構築します。ページを参照してください。 " Objective-Cシングルトンはどのように見えるべきですか? "そして、オブジェクトをグローバルにアクセス可能にするためにしたことは、インポートを適用するためのappName_Prefix.pchすべてのクラスのステートメント。このオブジェクトにアクセスして使用するには、クラスメソッドを実装して、独自の変数を含む共有インスタンスを返すだけです。

18
petershine

1. 2番目のView Controllerに最初のView Controllerのインスタンスを作成し、そのプロパティを@property (nonatomic,assign)にします。

2. このビューコントローラのSecondviewControllerインスタンスを割り当てます。

2. 選択操作が完了したら、最初のView Controllerに配列をコピーします。SecondViewをアンロードすると、FirstViewは配列データを保持します。

お役に立てれば。

18
kaar3k

以下のようにFirstViewControllerからSecondViewControllerにデータを渡す

例えば: 

FirstViewController文字列値として

StrFirstValue = @"first";

それで、以下のステップを使用して、この値を2番目のクラスに渡すことができます。

1> SecondViewController.hファイルに文字列オブジェクトを作成する必要があります

NSString *strValue;

2> .hファイルでの宣言の下に、次のようにプロパティを宣言する必要があります。 

@property (strong, nonatomic)  NSString *strSecondValue;

3>ヘッダー宣言の下のFirstViewController.mファイルでその値を合成する必要があります。

@synthesize strValue;

そしてFirstViewController.hで:

@property (strong, nonatomic)  NSString *strValue;

4> FirstViewControllerでは、どのメソッドから2番目のビューに移動するかを、そのメソッドのコードの下に書いてください。 

SecondViewController *secondView= [[SecondViewController alloc]     
initWithNibName:@"SecondViewController " bundle:[NSBundle MainBundle]];

[secondView setStrSecondValue:StrFirstValue];

[self.navigationController pushViewController:secondView animated:YES ];
16
Chris Alan

私は現在MCViewFactoryと呼ばれるプロジェクトを通してこの問題に対するオープンソースの解決策に貢献しています。

https://github.com/YetiHQ/manticore-iosviewfactory

アイデアは、あなたが見ているビューを管理するためにグローバルファクトリを使用し、ビュー間でデータを切り替えて渡すために「インテント」を使用して、Androidの意図パラダイムを模倣することです。すべてのドキュメントはgithubページにありますが、ここでいくつかハイライトします。

ファクトリを初期化しながら、すべてのビューを.XIBファイルに設定し、それらをアプリデリゲートに登録します。

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

// the following two lines are optional. 
[factory registerView:@"YourSectionViewController"]; 

これで、あなたのVCでは、新しいVCに移動してデータを渡したいときはいつでも、新しいインテントを作成してそのデータをその辞書(savedInstanceState)に追加します。次に、単にfactoryの現在の目的を設定します。

MCIntent* intent = [MCIntent intentWithSectionName:@"YourSectionViewController"];
[intent setAnimationStyle:UIViewAnimationOptionTransitionFlipFromLeft];
[[intent savedInstanceState] setObject:@"someValue" forKey:@"yourKey"];
[[intent savedInstanceState] setObject:@"anotherValue" forKey:@"anotherKey"];
// ...
[[MCViewModel sharedModel] setCurrentSection:intent];

これに準拠するビューはすべてMCViewControllerのサブクラスである必要があります。これにより、新しいonResume:メソッドをオーバーライドして、渡したデータにアクセスできるようになります。

-(void)onResume:(MCIntent *)intent {
    NSObject* someValue = [intent.savedInstanceState objectForKey:@"yourKey"];
    NSObject* anotherValue = [intent.savedInstanceState objectForKey:@"anotherKey"];

    // ...

    // ensure the following line is called, especially for MCSectionViewController
    [super onResume:intent];
}

何人かの人がこの解決策が便利で面白いと思うことを願っています。 

16
user2563044

次のview controller .hでプロパティを作成し、getterとsetterを定義します。

NextVCのNextVC.hにこのpropertyを追加してください

@property (strong, nonatomic) NSString *indexNumber;

追加する 

NextVC.mの@synthesize indexNumber;

そして最後

NextVC *vc=[[NextVC alloc]init];

vc.indexNumber=@"123";

[self.navigationController vc animated:YES];
13
Vivek Yadav

私はこれが殴打された主題であることを知っています、しかしSwiftの傾斜でこの質問に答えて、素朴な例が欲しい人のために。

ボタン、ラベルなどがないことを除いて上記と同じです。あるビューから次のビューにデータを渡すだけです。

ストーリーボードの設定

3つの部分があります。 

  1. 送り主
  2. セーグ
  3. 受信機

これは、それらの間にセグエがある非常に単純なビューレイアウトです。


Very simple view layout. Note : No navigation controller


これが送信者の設定です。


The Sender


これが受信機の設定です。


The Receiver


最後に、セグエの設定です。


The Segue Identifier


ビューコントローラ

これは単純なので、ボタンではなくアクションではなく、アプリケーションがロードされたときにデータを送信側から受信側に移動し、送信された値をコンソールに出力するだけです。

このページは最初にロードされた値を受け取り、それを渡します。

//
//  ViewControllerSender.Swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit


class ViewControllerSender: UIViewController {

    // THE STUFF - put some info into a variable
    let favoriteMovie = "Ghost Busters"


    override func viewDidAppear(animated: Bool) {
        // PASS IDENTIFIER - go to the recieving view controller.
        self.performSegueWithIdentifier("goToReciever", sender: self)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        //GET REFERENCE - ...to the receiver view.
        var viewControllerReceiver = segue.destinationViewController as? ViewControllerReceiver

        //PASS STUFF - pass the variable along to the target.
        viewControllerReceiver!.yourFavMovie = self.favoriteMovie

    }

}

このページはロード時に変数の値をコンソールに送信するだけです。この時点で、私たちのお気に入りの映画はその変数にあるはずです。

//
//  ViewControllerReceiver.Swift
//  PassDataBetweenViews
//
//  Created by Chris Cantley on 8/25/15.
//  Copyright (c) 2015 Chris Cantley. All rights reserved.
//

import UIKit

class ViewControllerReceiver: UIViewController {

    //Basic empty variable waiting for you to pass in your fantastic favorite movie.
    var yourFavMovie = ""

    override func viewDidLoad() {
        super.viewDidLoad()


        //And now we can view it in the console.
        println("The Movie is \(self.yourFavMovie)")

    }



}

それはあなたがセグエを使用したいがあなたがナビゲーションコントローラの下にあなたのページを持っていないならあなたがそれに取り組むことができる方法です。

実行されると自動的に受信者ビューに切り替わり、送信者から受信者に値が渡され、コンソールに値が表示されます。

Ghost Busters is a classic folks.

.xibファイルを使用しているときに委任がそのような操作を実行する唯一の解決策ですが、上記のすべての答えは、委任を使用する必要がある.xibファイルのstoryboardに対するものです。それが唯一の解決策です。 

もう1つの解決策は、シングルトンクラスパターンを使用して一度初期化し、それをアプリケーション全体で使用することです。 

10
user2786888

viewControlerOneからViewControllerTwoにデータを渡したい場合は、これらを試してください。 

viewControlerOne.hでこれらを行います。

 @property (nonatomic, strong) NSString *str1;

viewControllerTwo.hでこれらを行います。

 @property (nonatomic, strong) NSString *str2;

ViewControllerTwo.mでstr2を合成します。

@interface ViewControllerTwo ()
@end
@implementation ViewControllerTwo
@synthesize str2;

viewControlerOne.mでこれらを行います。

 - (void)viewDidLoad
 {
   [super viewDidLoad];

  // Data or string you wants to pass in ViewControllerTwo..
  self.str1 = @"hello world";

 }

ボタンクリックイベントでこれを行います..

-(IBAction)ButtonClicked
{ //Navigation on buttons click event from ViewControlerOne to ViewControlerTwo with transferring data or string..
  ViewControllerTwo *objViewTwo=[self.storyboard instantiateViewControllerWithIdentifier:@"ViewControllerTwo"];
  obj.str2=str1;
  [self.navigationController pushViewController: objViewTwo animated:YES];
}

viewControllerTwo.mでこれらを行います。

- (void)viewDidLoad
{
 [super viewDidLoad];
  NSLog(@"%@",str2);
}
10
krushnsinh

これを行うにはたくさんの方法があります。正しい方法を選ぶことが重要です。最も大きなアーキテクチャ上の決定の1つは、モデルコードがアプリ全体でどのように共有またはアクセスされるかにあります。

私はしばらく前にこのブログ記事を書きました: モデルコードの共有 。これが簡単な要約です。

共有データ

1つの方法は、View Controller間でモデルオブジェクトへのポインタを共有することです。 

  • データを設定するための(NavigationまたはTab Bar Controller内の)View Controllerのブルートフォース反復
  • PrepareForSegue(ストーリーボードの場合)またはinit(プログラムの場合)にデータを設定します。

Segueの準備が最も一般的なので、ここに例があります。

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var next = segue.destinationViewController as NextViewController
    next.dataSource = dataSource
}

独立アクセス

もう1つの方法は、一度にデータでいっぱいになった画面を処理し、View Controllerを互いに結合するのではなく、各View Controllerを単一のデータソースに結合して独立して取得できるようにすることです。 

これを私が見た最も一般的な方法は シングルトン インスタンスです。したがって、シングルトンオブジェクトがDataAccessであれば、UIViewControllerのviewDidLoadメソッドで次の操作を実行できます。

func viewDidLoad() {
    super.viewDidLoad()
    var data = dataAccess.requestData()
}

データの受け渡しにも役立つ追加のツールがあります。

  • キー値監視
  • NS通知
  • コアデータ
  • NSFetchedResultsController
  • 情報源

コアデータ

コアデータのいいところは、逆の関係にあるということです。それで、単にNotesViewControllerにnotesオブジェクトを渡したいのであれば、それはノートブックのような他のものと逆の関係になるでしょう。 NotesViewControllerでノートブックのデータが必要な場合は、次のようにしてオブジェクトグラフに戻ることができます。

let notebookName = note.notebook.name

私のブログ記事でこれについてもっと読んでください: モデルコードの共有

10
Korey Hinton

NewsViewController

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tbl_View deselectRowAtIndexPath:indexPath animated:YES];
  News *newsObj = [newstitleArr objectAtIndex:indexPath.row];
  NewsDetailViewController *newsDetailView = [[NewsDetailViewController alloc] initWithNibName:@"NewsDetailViewController" bundle:nil];

  newsDetailView.newsHeadlineStr = newsObj.newsHeadline;

  [self.navigationController pushViewController:newsDetailView animated:YES];
}

NewsDetailViewController.h

@interface NewsDetailViewController : UIViewController
@property(nonatomic,retain) NSString *newsHeadlineStr;
@end

NewsDetailViewController.m

@synthesize newsHeadlineStr;
10
Mohsin Sabasara

アプリケーションデリゲートにデータを保存して、アプリケーションのView Controller間でアクセスできます。アプリデリゲートの共有インスタンスを作成するだけです。

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

例えば

あなたがNSArray object *arrayXYZを宣言するならば、あなたはappDelegate.arrayXYZによってそれをどんなView Controllerででもアクセスすることができます

10
ak_tyagi

ユーザーが選択した内容をキャンセルできる場合は、NSProxyをベースにしたModelオブジェクトとMockオブジェクトを使用してデータをコミットまたは破棄するという考え方が好きです。 

単一のオブジェクトまたは複数のオブジェクトであるためデータの受け渡しが簡単で、UINavigationControllerコントローラとした場合、モデルへの参照を内部に保持でき、プッシュされたすべてのView ControllerはNavigation Controllerから直接アクセスできます。

8
highmaintenance

あるビューコントローラから別のビューコントローラにデータを送信したい場合は、次のようにします。

ViewControllerがあるとしましょう:ViewControllerとNewViewController。

viewController.hで

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
{
    IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;
}

@property (nonatomic,retain) IBOutlet UITextField *mytext1,*mytext2,*mytext3,*mytext4;

-(IBAction)goToNextScreen:(id)sender;

@end

viewController.m内

#import "ViewController.h"

#import "NewViewController.h"

@implementation ViewController
@synthesize mytext1,mytext2,mytext3,mytext4;

-(IBAction)goToNextScreen:(id)sender
{
    NSArray *arr = [NSArray arrayWithObjects:mytext1.text,mytext2.text,mytext3.text,mytext4.text, nil];


    NewViewController *newVc = [[NewViewController alloc] initWithNibName:@"NewViewController" bundle:nil];

    newVc.arrayList = arr;

    [self.navigationController pushViewController:newVc animated:YES];

}

NewViewController.h内

#import <UIKit/UIKit.h>

@interface NewViewController : UITableViewController
{
    NSArray *arrayList;

    NSString *name,*age,*dob,*mobile;

}

@property(nonatomic, retain)NSArray *arrayList;

@end

NewViewController.m内

#import "NewViewController.h"

#import "ViewController.h"

@implementation NewViewController
@synthesize arrayList;

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    // Return the number of rows in the section.
    return [arrayList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];      
    }
    // Configure the cell...
    cell.textLabel.text = [arrayList objectAtIndex:indexPath.row];
    return cell;


}

@end

このようにして、あるView Controllerから別のView Controllerにデータを渡すことができます。

8
Sabs

私はdidSelectRowAtPathメソッドを使ってこれを複雑にすることについて多くの人が見ています。私の例ではCore Dataを使用しています。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

    //this solution is for using Core Data
    YourCDEntityName * value = (YourCDEntityName *)[[self fetchedResultsController] objectAtIndexPath: indexPath];

    YourSecondViewController * details = [self.storyboard instantiateViewControllerWithIdentifier:@"nameOfYourSecondVC"];//make sure in storyboards you give your second VC an identifier

    //Make sure you declare your value in the second view controller
    details.selectedValue = value;

    //Now that you have said to pass value all you need to do is change views
    [self.navigationController pushViewController: details animated:YES];

}

メソッド内に4行のコードを入力すれば完了です。 

7
App Dev Guy

実際にはうまくいくであろうView Controller通信を実行するためのさまざまな方法を提供しているこの質問に対する多くの回答がありますが、私はどこが実際に最も適しているか、そしてどれが避けるべきか言及しません。

実際には、私の意見では、いくつかの解決策のみが推奨されます。

  • データを転送するには:
    • ストーリーボードを使用してセグエスを使用する場合はUIViewControllerprepare(for:sender:)メソッドをオーバーライドする
    • コードを介してView Controllerの遷移を実行するときに、イニシャライザまたはプロパティを介してデータを渡す
  • データを逆方向に渡すには
    • アプリの共有状態を更新します(上記のいずれかの方法でView Controller間で転送できます)。
    • 委任を使用する
    • くつろぎのセグエを使用する

使用しないことをお勧めするソリューション:

  • 委任を使用せずに、以前のコントローラを直接参照する
  • シングルトンを通してデータを共有する
  • アプリデリゲートを介してデータを渡す
  • ユーザーデフォルトを介してデータを共有する
  • 通知を介したデータの受け渡し

これらのソリューションは、短期的には機能しますが、依存関係が多すぎてアプリケーションのアーキテクチャを乱し、後で問題を引き起こす可能性があります。

興味のある人のために、私はこれらの点をより深く取り上げ、そしてさまざまな欠点を強調したいくつかの記事を書きました:

5

あるViewControllerから別のViewControllerにデータを渡すための3つのタイプがあります。

  1. プログラム的に
  2. セグエ
  3. ユーザーデフォルト

デモプロジェクトのリンクはこちら - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers

プログラム的に enter image description here

Segue enter image description here

UserDefaults enter image description here

デモプロジェクトのリンクはこちら - https://github.com/kamanijasmin13/Swift-Pass-data-between-viewcontrollers

4
Kamani Jasmin

スイフト5

Well Matt Priceの回答 データの受け渡しにはまったく問題ありませんが、最新のSwiftバージョンで書き直すつもりです。元の記事はObjectiveにあるので、新しいプログラマは新しいSyntaxやメソッド/フレームワークのせいでやりがいがあると思います。 -C.

View Controller間でデータを渡す方法は複数あります。

  1. ナビゲーションコントローラプッシュの使用
  2. Segueを使う
  3. デリゲートを使う
  4. 通知オブザーバの使用
  5. ブロックを使う

私は最新のiOSフレームワークでSwiftで彼の論理を書き直すつもりです


ナビゲーションコントローラプッシュによるデータの受け渡し ViewControllerAからViewControllerBへ

ステップ1 - ViewControllerBで変数を宣言する

var isSomethingEnabled = false

ステップ2 ViewControllerBのViewDidLoadメソッドで変数を印刷する

override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue, navigation Push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }

ステップ3 ViewControllerAでNavigation Controllerを押しながらデータを渡す

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
        viewControllerB.isSomethingEnabled = true
        if let navigator = navigationController {
            navigator.pushViewController(viewControllerB, animated: true)
        }
    }

だからここに完全なコードです:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Passing Data through Navigation PushViewController
    @IBAction func goToViewControllerB(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.isSomethingEnabled = true
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:  - Variable for Passing Data through Navigation Push   
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through navigation Push
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

Segueを通してデータを渡す ViewControllerAからViewControllerBへ

ステップ1 - ViewControllerAからViewControllerBへのSegueを作成し、ストーリーボードでIdentifier = showDetailSegueを以下のように指定します。

enter image description here 

ステップ2 ViewControllerBで isSomethingEnabled という名前の実行可能ファイルを宣言し、その値を印刷します。

ステップ3 ViewControllerAでは、Segueを渡すときにisSomethingEnabledの値を渡します。

だからここに完全なコードです:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:  - - Passing Data through Segue  - - 
    @IBAction func goToViewControllerBUsingSegue(_ sender: Any) {
        performSegue(withIdentifier: "showDetailSegue", sender: nil)
    }

    //Segue Delegate Method
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "showDetailSegue") {
            let controller = segue.destination as? ViewControllerB
            controller?.isSomethingEnabled = true//passing data
        }
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {
    var isSomethingEnabled = false

    override func viewDidLoad() {
        super.viewDidLoad()
        //Print value received through segue
        print("Value of 'isSomethingEnabled' from ViewControllerA : ", isSomethingEnabled)
    }
}

デリゲートを介してデータを渡す ViewControllerBからViewControllerAへ

手順1 - プロトコルの宣言ViewControllerBDelegateViewControllerBファイル内、ただしクラス外

protocol ViewControllerBDelegate: NSObjectProtocol {

    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

ステップ2 ViewControllerBでデリゲート変数インスタンスを宣言する

var delegate: ViewControllerBDelegate?

ステップ3 ViewControllerBのviewDidLoadメソッド内にデリゲート用のデータを送信する

delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")

ステップ4 ViewControllerAでViewControllerBDelegateを確認する

class ViewControllerA: UIViewController, ViewControllerBDelegate  {
// to do
}

ステップ5. ViewControllerAにデリゲートを実装することを確認します

if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self//confirming delegate
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }

ステップ6 ViewControllerAでデータを受け取るためのデリゲートメソッドを実装する

func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

だからここに完全なコードです:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController, ViewControllerBDelegate  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //Delegate method
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?) {
        print("Value from ViewControllerB's Delegate", item!)
    }

    @IBAction func goToViewControllerForDelegate(_ sender: Any) {

        if let viewControllerB = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewControllerB") as? ViewControllerB {
            viewControllerB.delegate = self
            if let navigator = navigationController {
                navigator.pushViewController(viewControllerB, animated: true)
            }
        }
    }
}

ViewControllerB

import UIKit

//Protocol decleare
protocol ViewControllerBDelegate: NSObjectProtocol {
    // Classes that adopt this protocol MUST define
    // this method -- and hopefully do something in
    // that definition.
    func addItemViewController(_ controller: ViewControllerB?, didFinishEnteringItem item: String?)
}

class ViewControllerB: UIViewController {
    var delegate: ViewControllerBDelegate?

    override func viewDidLoad() {
        super.viewDidLoad()
        //MARK:  - - - -  Set Data for Passing Data through Delegate  - - - - - -
        delegate?.addItemViewController(self, didFinishEnteringItem: "Data for ViewControllerA")
    }
}

通知オブザーバを介してデータを渡す ViewControllerBからViewControllerAへ

ステップ1. ViewControllerBの通知オブザーバにデータを設定して投稿する

let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)

ステップ2. ViewControllerAに通知オブザーバを追加する

NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)

ステップ3. ViewControllerAで通知データ値を受け取る

@objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }

だからここに完全なコードです:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController{

    override func viewDidLoad() {
        super.viewDidLoad()

        // add observer in controller(s) where you want to receive data
        NotificationCenter.default.addObserver(self, selector: #selector(self.methodOfReceivedNotification(notification:)), name: Notification.Name("NotificationIdentifier"), object: nil)
    }

    //MARK: Method for receiving Data through Post Notification 
    @objc func methodOfReceivedNotification(notification: Notification) {
        print("Value of notification : ", notification.object ?? "")
    }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Post Notification
        let objToBeSent = "Test Message from Notification"
        NotificationCenter.default.post(name: Notification.Name("NotificationIdentifier"), object: objToBeSent)
    }
}

ブロックを介してデータを渡す ViewControllerBからViewControllerAへ

ステップ1. ViewControllerBでブロックを宣言する

var authorizationCompletionBlock:((Bool) - >())? = {_ in}

ステップ2. ViewControllerBでデータをブロックに設定する

if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }

ステップ3. ViewControllerAでブロックデータを受信する

//Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }

だからここに完全なコードです:

ViewControllerA

import UIKit

class ViewControllerA: UIViewController  {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //MARK:Method for receiving Data through Block
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if (segue.identifier == "showDetailSegue") {
                let controller = segue.destination as? ViewControllerB
                controller?.isSomethingEnabled = true

                //Receiver Block
                controller!.authorizationCompletionBlock = { isGranted in
                    print("Data received from Block is :", isGranted)
                }
            }
        }
}

ViewControllerB

import UIKit

class ViewControllerB: UIViewController {

    //MARK:Variable for Passing Data through Block
    var authorizationCompletionBlock:((Bool)->())? = {_ in}

    override func viewDidLoad() {
        super.viewDidLoad()

        //MARK:Set data for Passing Data through Block
        if authorizationCompletionBlock != nil
        {
            authorizationCompletionBlock!(true)
        }
    }
}

あなたは私のGitHubで完全なサンプルアプリケーションを見つけることができます あなたがこれに関して何か質問があれば私に知らせてください。

3
swiftBoy

これは、 チュートリアル が欲しい人にとっては本当に素晴らしいです。これがサンプルコードです:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"myIdentifer]) {
        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        myViewController *destViewController = segue.destinationViewController;
        destViewController.name = [object objectAtIndex:indexPath.row];
    }
}
3

通知センターを使用する

スイフト3用

let imageDataDict:[String: UIImage] = ["image": image]

  // post a notification
  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
  // `default` is now a property, not a method call

 // Register to receive notification in your class
 NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

 // handle notification
 func showSpinningWheel(_ notification: NSNotification) {
        print(notification.userInfo ?? "")
        if let dict = notification.userInfo as NSDictionary? {
            if let id = dict["image"] as? UIImage{
                // do something with your image
            }
        }
 }

スイフト4用

let imageDataDict:[String: UIImage] = ["image": image]

  // post a notification
  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "notificationName"), object: nil, userInfo: imageDataDict) 
  // `default` is now a property, not a method call

 // Register to receive notification in your class
 NotificationCenter.default.addObserver(self, selector: #selector(self.showSpinningWheel(_:)), name: NSNotification.Name(rawValue: "notificationName"), object: nil)

 // handle notification
 @objc func showSpinningWheel(_ notification: NSNotification) {
        print(notification.userInfo ?? "")
        if let dict = notification.userInfo as NSDictionary? {
            if let id = dict["image"] as? UIImage{
                // do something with your image
            }
        }
 }
3
Sachin Rasane

あるVCから他にデータを送信するには、次の簡単な方法を使用します。

YourNextVC *nxtScr = (YourNextVC*)[self.storyboard  instantiateViewControllerWithIdentifier:@"YourNextVC"];//Set this identifier from your storyboard

nxtScr.comingFrom = @"PreviousScreen"l
[self.navigationController nxtScr animated:YES];
2
Dalvik

それでも、デリゲートシステムやstoryboardSegueを使用して作業できる方法はほとんどありません。 

1- As working with setter and getter method like in viewController.h
   @property (retain, nonatomic) NSString *str;
   now, in viewController.m
   @synthesize str;


   here i have pdf url and segue to another viewController like this and pdfObject is my pdfModel basicilly is NSOBJECT class.  

   str =[NSString stringWithFormat:@"%@",pdfObject.objPath];
NSLog(@"pdfUrl :***: %@ :***:",pdfUrl);

[self performSegueWithIdentifier:@"programPDFViewController_segue" sender:self];

プラグママーク - ナビゲーション

  // In a storyboard-based application, you will often want to do a little preparation before navigation

 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    if ([[segue identifier] isEqualToString:@"programPDFViewController_segue"]){
    programPDFViewController *pdfVC = [segue destinationViewController];
    [pdfVC setRecievedPdfUrl:str];

   }
 }

今正常に私は私のpdfのurl文字列と他のViewControllerを受け取り、webviewでその文字列を使います... 

2-このようなデリゲートを扱うとき、私はdateFormatter、sharedInstance、EscapeWhiteSpaceCharacters、convertImageToGrayScaleなどの私のメソッドを含むユーティリティの1つのNSObjectクラスを持っています。

この場合は、utilities.h で作成した文字列変数を一度だけ使用して、データをあるビューコントローラから別のビューコントローラに解析するときに変数を作成する必要はありません。そしてまた使った

  @interface Utilities : NSObject

  Utilities.h
 +(Utilities*)sharedInstance;

 @property(nonatomic,retain)NSString* strUrl;

utilities.mに

   @implementation utilities


  +(utilities*)sharedInstance
  {
  static utilities* sharedObj = nil;
  if (sharedObj == nil) {
    sharedObj = [[utilities alloc] init];
    }
   return sharedObj;
  }

now its done come to your firstViewController.m and call delegate

NSString*str =[NSString stringWithFormat:@"%@",pdfObject.objPath];

[Connection sharedInstance].strUrl=nil;
[Connection sharedInstance].strUrl=str;

 Now go to you secondViewController.m directly use it without creating variable 

 in viewwillapear what i did

 -(void)viewWillAppear:(BOOL)animated{
     [super viewWillAppear:YES];

   [self webViewMethod:[Connection sharedInstance].strUrl];

 }


 -(void)WebViewMethod:(NSString)Url{

 // working with webview enjoy coding :D

 }

この委任作業はメモリ管理で信頼できます。 

2
Nayab Khan

ブロック/クロージャとカスタムコンストラクタをお勧めします。

FirstViewControllerからSecondViewControllerに文字列を渡す必要があるとします。

あなたの最初のView Controller。 

class FirstViewController : UIViewController {

    func moveToViewControllerB() {

        let second_screen = SecondViewController.screen(string: "DATA TO PASS", call_back: {
            [weak self] (updated_data) in
            ///This closure will be called by second view controller when it updates something
        })
        self.navigationController?.pushViewController(second_screen, animated: true)
    }


}

あなたのセカンドビューコントローラ

class SecondViewController : UIViewController {

    var incoming_string : String?
    var call_back : ((String) -> Void)?

    class func screen(string: String?, call_back : ((String) -> Void)?) -> SecondViewController {

        let me = SecondViewController(nibName: String(describing: self), bundle: Bundle.main);
        me.incoming_string = string
        me.call_back = call_back
        return me
    }

    // Suppose its called when you have to update FirstViewController with new data.
    func updatedSomething() {

        //Executing block that is implemented/assigned by the FirstViewController.
        self.call_back?("UPDATED DATA")
    }

}
1
Umair

ソースビューコントローラから宛先ビューコントローラへのプッシュセグエを作成し、以下のような識別子名を付けることができます。 enter image description here

このようにdidselectRowAtから実行する必要があります。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    performSegue(withIdentifier: "segue", sender: self)
}

そして下の関数から選択した項目の配列を渡すことができます。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    print(indexNumber!)
    let VC = segue.destination as! AddTransactionVC
   VC.val = CategoryData[indexNumber!] . //You can pass here entire array instead of array element.

}

そして、あなたは目的のviewcontrollerのviewdidloadの中の値をチェックし、それからデータベースにそれを保存する必要があります。

override func viewDidLoad{
 if val != ""{
        btnSelectCategory.setTitle(val, for: .normal)
    }
}
1
Parth Barot

私は代表者とセグエなしでそれを作ることを好みます。これは、カスタムinitを使って、またはオプションの値を設定することによって実行できます。

1.カスタムinit

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB(string: "Blabla", completionClosure: { success in
      print(success)
    })
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  private let completionClosure: ((Bool) -> Void)
  init(string: String, completionClosure: ((Bool) -> Void)) {
    self.completionClosure = completionClosure
    super.init(nibName: nil, bundle: nil)
    title = string
  }

  func finishWork() {
    completionClosure()
  }
}

2.オプションの変数

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB()
    viewController.string = "Blabla"
    viewController.completionClosure = { success in
      print(success)
    }
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  var string: String? {
    didSet {
      title = string
    }
  }
  var completionClosure: ((Bool) -> Void)?

  func finishWork() {
    completionClosure?()
  }
}
1

これを行うApple方法は、セグエを使用することです。 prepareForSegue()関数を使用する必要があります

素晴らしいチュートリアルがたくさんありますが、ここにその1つがあります。 https://www.iphonelife.com/content/unleash-your-inner-app-developer-part-21-passing-data-between-controllers

また、セグエの使用に関するAppleドキュメントを参照してください。 https://developer.Apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html

1
tmac_balla

もっと簡単な方法はこちらです。

グローバル変数を使うだけです。次のクラスに渡すために必要なオブジェクトまたは変数を宣言します。

たとえば、classAclassBの2つのクラスがあります。

classAには通常以下が含まれます。

#import "classA.h"

@interface classA()

@end

@implementation classA

-(void)viewDidLoad
{
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

そしてclassBは以下を含みます。

#import "classB.h"

@interface classB()

@end

@implementation classB

-(void)viewWillLoad
{
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

今度は、2番目のクラスclassBclassAにインポートします。

#import "classA.h"
#import "classB.h"  //---import classB to classA.
@interface classA()

@end

@implementation classA

-(void)viewDidLoad
{
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

これで、2番目のクラスclassB に移動するためのブリッジができました。変数またはオブジェクトをグローバルとして宣言するために、次のように最初のクラスの.mファイルで宣言します。

classA.h

#import "classA.h"
#import "classB.h"
@interface classA()

@end
NSString *temp;  //----declare any object/variable as global.
@implementation classA

-(void)viewDidLoad
{
    ...
    temp=@"Hello";
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

ここでオブジェクトtempは任意のクラスのグローバルオブジェクトまたはグローバル変数にアクセスするためのクラスNSStringのグローバルオブジェクトです。2番目のクラスのオブジェクトまたは変数を再宣言するだけです。例えば。下記のとおり:

classB.m

#import "classB.h"

@interface classB()

@end
extern NSString *temp;  //----use `extern` keyword for using the global object/variable in classB that was declared in classA.
@implementation classB

-(void)viewDidLoad
{
    ...
    LabeL.text=temp;
    ...
}
-(void)didReceiveMemoryWarning
{
    ...
}

これで、2番目のクラスから値にアクセスできるようになりました。単純な!..このメソッドは、任意の数のクラスに対して実行できます。

注意:

2番目のクラスの.hファイルを最初のクラスにインポートする必要があります。しかし、第1クラスの.hファイルを第2クラスにインポートする必要はありません。

橋があるならば、それは両側に行くことができるはずです。

これが役に立つと思います。私が同じ状況にあったとき、それは私を助けました。

0
soorej babu

IOS用のアプリケーションを作成するときは、常にMVCの概念に従う必要があります。 ViewControllerから別のViewControllerにデータを渡す場合が2つあります。

  1. 階層内に "A" ViewContollerがあり、あなたが next / viewcontrollerである "B"にデータを送りたいとき。この場合はSegueを使う必要があります。セグエの識別子を設定してから、「A」VCに次のコードを記述します。

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "A to B segue identifier" {
            let bViewController = segue.destination as! UIDocumentBrowserViewController
            bViewController.data = someData
        }
    }
    
  2. モーダル(または埋め込み)としてAを自分自身で開いたBがあるとき。これでBビューコントローラはその親について盲目になるはずです。そのため、データをAに送り返す最良の方法はDelegationを使用することです。 Bビューコントローラとdelegateプロパティにデリゲートプロトコルを作成します。そのためBはデリゲートに報告(データを送り返す)します。 Aビューコントローラでは、Bビューコントローラのデリゲートプロトコルを実装し、prepare(forSegue:)メソッドでselfdelegateビューコントローラのBプロパティとして設定します。

これはどのように正しく実装されるべきかです。それが役に立てば幸い

0
Shahin