1464

私はiOSとObjective-C、そしてMVCパラダイム全体に不慣れで、次のことにこだわっています。

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

あるビューから別のビューにデータを転送するにはどうすればよいですか? 配列で選択を保持しますUITableViewが、それを前のデータ入力フォーム ビューに戻して、フォームの送信時に他のデータと一緒に Core Data に保存できるようにするにはどうすればよいですか?

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

これを実行する正しい方法は何ですか?どうすればよいですか?

4

46 に答える 46

1734

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

データの転送

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

この例ではViewControllerAViewControllerB

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

  1. のプロパティをViewControllerB.h作成するBOOL

     @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. あなたはViewControllerAそれについてそれを伝える必要があるViewControllerBので、

     #import "ViewControllerB.h"
    

次に、たとえばビューをロードする場合、didSelectRowAtIndexまたは一部をロードする場合は、ナビゲーションスタックにプッシュする前にIBAction、プロパティを設定する必要があります。ViewControllerB

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

これは値に設定isSomethingEnabledViewControllerBれます。BOOLYES

セグエを使用してデータを転送する

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

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

したがって、BOOLfromViewControllerAをtoに渡すViewControllerBには、次のようにします。

  1. のプロパティをViewControllerB.h作成するBOOL

     @property (nonatomic, assign) BOOL isSomethingEnabled;
    
  2. あなたはViewControllerAそれについてそれを伝える必要があるViewControllerBので、

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

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

     -(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;
        }
    }

これは値に設定isSomethingEnabledViewControllerBれます。BOOLYES

データを返す

からデータを返すには、プロトコルとデリゲートまたはブロックViewControllerBを使用するViewControllerA必要があります。後者は、コールバックの緩く結合されたメカニズムとして使用できます。

これを行うためにViewControllerA、のデリゲートを作成しViewControllerBます。これによりViewControllerB、メッセージを送り返してViewControllerA、データを送り返すことができます。

ViewControllerA代理人になるには、指定する必要のあるのプロトコルにViewControllerB準拠している必要があります。ViewControllerBこれによりViewControllerA、実装する必要のあるメソッドがわかります。

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

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

     @property (nonatomic, weak) id <ViewControllerBDelegate> delegate;
    
  3. では、 ViewControllerをポップViewControllerBしたときにメッセージを呼び出します。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. ViewControllerプログラミングガイドの委任を使用した他のViewControllerとの通信
  2. デリゲートパターン

NSNotificationセンター

これは、データを渡すもう1つの方法です。

// Add an 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サブクラス、またはその他のクラスを指定できます)

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

この例では、コントローラーBからコントローラー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];
}

ブロックの別の実用例

于 2012-03-16T11:39:33.740 に答える
217

迅速

ここや Stack Overflow の周りにはたくさんの説明がありますが、初心者で基本的なことを機能させようとしている場合は、この YouTube チュートリアルを見てみてください (最終的にその方法を理解するのに役立ちました)。

次のView Controllerにデータを渡す

以下は、ビデオに基づいた例です。アイデアは、最初のビュー コントローラーのテキスト フィールドから 2 番目のビュー コントローラーのラベルに文字列を渡すことです。

ここに画像の説明を入力してください

Interface Builder でストーリーボード レイアウトを作成します。セグエを作成するControlには、ボタンをクリックして、2 番目のビュー コントローラーにドラッグします。

最初のView Controller

最初の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!
    }

}

2 番目のビュー コントローラー

2 番目のビュー コントローラーのコードは次のとおりです。

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
    }

}

忘れないで

  • UITextFieldとのコンセントを接続しUILabelます。
  • Interface Builderで、1 つ目と 2 つ目の View Controller を適切な Swift ファイルに設定します。

前のView Controllerにデータを戻す

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

以下は、ビデオに基づいた例です (いくつかの変更が加えられています)。

ここに画像の説明を入力してください

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

最初のView Controller

最初の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 番目のビュー コントローラーとプロトコル

2 番目のビュー コントローラーのコードは次のとおりです。

import UIKit

// Protocol used for sending data back
protocol DataEnteredDelegate: AnyObject {
    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 番目のビュー コントローラーから 1 番目のビュー コントローラーにデータを送り返すことができるはずです。

于 2015-08-11T06:35:25.237 に答える
141

MVC の M は「モデル」を表し、MVC パラダイムでは、モデル クラスの役割はプログラムのデータを管理することです。モデルはビューの反対です。ビューはデータの表示方法を知っていますが、データの処理方法については何も知りません。一方、モデルはデータの操作方法についてはすべて知っていますが、表示方法については何も知りません。モデルは複雑になることがありますが、複雑である必要はありません。アプリのモデルは、文字列や辞書の配列のように単純な場合があります。

コントローラーの役割は、ビューとモデルの間を仲介することです。したがって、1 つ以上のビュー オブジェクトと 1 つ以上のモデル オブジェクトへの参照が必要です。モデルが辞書の配列であり、各辞書がテーブル内の 1 つの行を表すとします。アプリのルート ビューにはそのテーブルが表示され、ファイルから配列を読み込む役割を果たしている可能性があります。ユーザーがテーブルに新しい行を追加することを決定した場合、ボタンをタップすると、コントローラーが新しい (変更可能な) 辞書を作成して配列に追加します。行を埋めるために、コントローラは詳細ビュー コントローラを作成し、それに新しいディクショナリを提供します。詳細ビュー コントローラーは、辞書に入力して返します。ディクショナリはすでにモデルの一部であるため、他に何もする必要はありません。

于 2011-03-06T13:49:13.553 に答える
103

iOS の別のクラスでデータを受信するには、さまざまな方法があります。例えば ​​-

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

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

Controller1 と Controller2の 2 つのコントローラーを使用して理解できます。

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 つ以上のパラメーターを渡す必要がある場合は、値をモデル クラスに格納し、その 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. 2 番目のクラスのプライベート変数を設定し、カスタム関数を呼び出して値を渡すことによって値を初期化します。
  2. setProperties は、setter メソッドを使用して直接初期化することでそれを行います。
  3. 何らかの方法で相互に関連する 3 ~ 4 個以上の値を渡し、モデル クラスを作成してそのオブジェクトに値を設定し、上記のプロセスのいずれかを使用してオブジェクトを渡します。
于 2014-04-08T10:24:29.583 に答える
88

さらに調査した結果、プロトコルデリゲートが正しい/Appleがこれを行うのに適した方法であることがわかりました。

私はこの例を(iPhone開発SDKで)使用することになりました:

ビュー コントローラと他のオブジェクト間でデータを共有する

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

于 2011-03-13T21:20:09.367 に答える
42

OPはView Controllerについて言及していませんでしたが、非常に多くの回答がそうしているので、あるView Controllerから別のView Controllerにデータを渡したいときに、LLVMの新機能のいくつかがこれを簡単にすることを可能にしたいと思いました。いくつかの結果が返ってきます。

ストーリーボードのセグエ、ARC、および LLVM ブロックにより、これがこれまで以上に簡単になりました。上記のいくつかの回答では、ストーリーボードとセグエについて既に言及されていましたが、まだ委任に依存していました。デリゲートの定義は確かに機能しますが、ポインターやコード ブロックを渡す方が簡単だと感じる人もいます。

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

セグエ グルーの簡単な例を 2 つ示します。1 つ目は入力用に渡された 1 つのパラメーターを示し、2 つ目は出力用に渡された単純なものです。

// 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];
    }];
}
于 2013-02-21T22:26:12.650 に答える
32

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

ファイル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];
 }
于 2013-11-18T12:48:24.273 に答える
31

これは非常に古い答えであり、これはアンチパターンです。代理人をご利用ください。このアプローチを使用しないでください!!

1. 2 番目のビュー コントローラーで最初のビュー コントローラーのインスタンスを作成し、そのプロパティを作成します@property (nonatomic,assign)

2.SecondviewControllerこのView Controllerのインスタンスを割り当てます。

2.選択操作が終了したら、アレイを最初のView Controllerにコピーします。2 番目のビューをアンロードすると、最初のビューに配列データが保持されます。

于 2012-05-23T13:08:30.760 に答える
27

これはそれを行う方法ではありません。デリゲートを使用する必要があります。

ViewController1 と ViewController2 の 2 つのビュー コントローラーがあり、このチェックは最初のコントローラーにあり、その状態が変化すると、ViewController2 で何かをしたいとします。適切な方法でそれを達成するには、以下を実行する必要があります。

プロジェクトに新しいファイルを追加します (Objective-C プロトコル) メニューの[ファイル] → [新規] 。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
于 2014-09-01T19:46:45.523 に答える
25

あるviewControllerから別のviewControllerにデータを送信したい場合は、次の方法があります。

viewControllers があるとします: 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 にデータを渡す方法です。;)

于 2012-07-29T10:28:43.177 に答える
23

Swiftの傾斜があり、必要最小限の例が必要な場合は、セグエを使用して回避する場合にデータを渡すための私の頼りになる方法を次に示します。

上記と似ていますが、ボタンやラベルなどはありません。あるビューから次のビューにデータを渡すだけです。

ストーリーボードのセットアップ

3 つの部分があります。

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

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


非常にシンプルなビュー レイアウト。 注: ナビゲーション コントローラーはありません


送信側の設定はこちら


送り主


受信機の設定はこちら。


受信機


最後に、セグエのセットアップです。


セグエ識別子


ビューコントローラー

これをシンプルに保つため、ボタンやアクションはありません。アプリケーションのロード時に送信側から受信側にデータを移動し、送信された値をコンソールに出力するだけです。

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

import UIKit


class ViewControllerSender: UIViewController {

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

    override func viewDidAppear(animated: Bool) {
        // PASS IDENTIFIER - go to the receiving 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

    }
}

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

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)")

    }
}

これは、セグエを使用する必要があり、ナビゲーション コントローラーの下にページがない場合に対処する方法です。

実行されると、レシーバー ビューに自動的に切り替わり、値がセンダーからレシーバーに渡され、値がコンソールに表示されます。

ゴーストバスターズは古典的な人々です。

于 2015-08-25T15:28:28.837 に答える
20

以下のように 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 ];
    
于 2013-10-23T10:58:59.457 に答える
20

私の場合、アプリのほぼすべての場所からデータにアクセスできるグローバル オブジェクトとして機能するシングルトン クラスを使用しました。

最初に、シングルトン クラスを作成します。私のObjective-Cシングルトンはどのように見えるべきですか?ページを参照してください。.

そして、オブジェクトをグローバルにアクセスできるようにするためにappName_Prefix.pch、すべてのクラスに import ステートメントを適用するためにインポートしました。

このオブジェクトにアクセスして使用するには、独自の変数を含む共有インスタンスを返すクラス メソッドを実装するだけです。

于 2011-03-06T14:03:19.477 に答える
19

私は現在、MCViewFactory というプロジェクトを通じて、この問題に対するオープン ソース ソリューションに貢献しています。

マンティコア iOS ビュー ファクトリー

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

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

// Register activities

MCViewFactory *factory = [MCViewFactory sharedFactory];

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

これで、ビュー コントローラー (VC) で、新しい VC に移動してデータを渡したいときはいつでも、新しいインテントを作成し、そのディクショナリ (savedInstanceState) にデータを追加します。次に、ファクトリの現在の意図を設定します。

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];
}
于 2014-09-16T17:18:29.983 に答える
15

次のファイルでプロパティを作成し、view controller .hゲッターとセッターを定義します。

これpropertyを nextVC の NextVC.h に追加します。

@property (strong, nonatomic) NSString *indexNumber;

追加

@synthesize indexNumber; NextVC.mで

そして最後

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

vc.indexNumber = @"123";

[self.navigationController vc animated:YES];
于 2014-01-02T12:29:49.203 に答える
11

これを行うにはたくさんの方法があり、適切な方法を選択することが重要です。おそらく、最大のアーキテクチャ上の決定事項の 1 つは、アプリ全体でモデル コードを共有またはアクセスする方法にあります。

しばらく前に、これについてのブログ記事を書きました:モデル コードの共有。簡単な要約は次のとおりです。

共有データ

1 つの方法は、ビュー コントローラー間でモデル オブジェクトへのポインターを共有することです。

  • データを設定するためのビュー コントローラー (ナビゲーションまたはタブ バー コントローラー) でのブルート フォース反復
  • prepareForSegue (ストーリーボードの場合) または init (プログラムの場合) でデータを設定します。

セグエの準備が最も一般的であるため、ここに例を示します。

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通知
  • コアデータ
  • NSFetchedResultsコントローラー
  • 情報源

コアデータ

Core Data の良い点は、逆の関係があることです。したがって、NotesViewController に notes オブジェクトを与えたい場合は、ノートブックなどの他のものと逆の関係になるため、できます。NotesViewController のノートブックにデータが必要な場合は、次のようにしてオブジェクト グラフに戻ることができます。

let notebookName = note.notebook.name

詳細については、私のブログ投稿:モデル コードの共有を参照してください。

于 2015-01-29T17:35:29.710 に答える
11

ViewControllerOne から 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";
 }

O ボタン クリック イベントでは、次のようにします。

-(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);
}
于 2015-05-27T14:11:49.103 に答える
11

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

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

例えば

を宣言するNSArray object *arrayXYZと、任意のビュー コントローラで によってアクセスできますappDelegate.arrayXYZ

于 2015-05-29T12:34:45.160 に答える
10

委任は、.xib ファイルを使用しているときにこのような操作を実行する唯一のソリューションです。ただし、以前の回答はすべてstoryboard.xibs ファイルに対するものです。委任を使用する必要があります。それがあなたが使用できる唯一の解決策です。

別の解決策は、シングルトン クラス パターンを使用することです。一度初期化すると、アプリ全体で使用できます。

于 2013-09-17T09:10:20.677 に答える
10

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;
于 2013-10-24T12:07:54.967 に答える
8

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 行のコードで完了です。

于 2015-01-16T03:18:43.510 に答える
7

SwiftUI の場合

多くのビュー@EnvironmentObjectで使用する、よりスマートで簡単な方法と考えてください。@ObservedObjectビュー A でデータを作成し、それをビュー B、ビュー C、ビュー D に渡してから最終的に使用するのではなく、ビューでデータを作成して環境に配置すると、ビュー B、C、および D が自動的にアクセスできます。

注: 環境オブジェクトは祖先ビューによって提供される必要があります。SwiftUIが正しいタイプの環境オブジェクトを見つけられない場合、クラッシュが発生します。これはプレビューにも当てはまりますので、注意してください。

例として、ユーザー設定を保存するオブザーバブル オブジェクトを次に示します。

class UserSettings: ObservableObject {
     @Published var score = 0
}
于 2019-12-10T10:45:22.883 に答える
6

この質問には、実際に機能するView Controller通信を実行するさまざまな方法を提供する多くの回答がありますが、実際に使用するのに最適なものと避けるべきものについて言及されている場所はどこにもありません。

実際には、私の意見では、いくつかのソリューションのみが推奨されています。

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

使用しないことをお勧めする解決策:

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

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

興味のある方のために、これらの点をより深く扱い、さまざまな欠点を強調するいくつかの記事を書きました。

于 2016-12-03T15:27:48.387 に答える
4

ビュー コントローラー間でデータを渡す方法はいくつかあります。

  1. デリゲート プロトコル (逆方向)。
  2. NSNotification センター (双方向)。
  3. UserDefault (双方向)。
  4. Direct プロパティ (順方向)。
  5. 閉鎖(後方方向)。
  6. Segue (順方向)。
于 2021-04-17T17:01:56.877 に答える
3

これは、必要な人にとって本当に素晴らしいチュートリアルです。コード例は次のとおりです。

- (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];
    }
}
于 2015-09-28T09:00:00.900 に答える
2

あるビュー コントローラー (VC) から別のビュー コントローラーにデータを送信するには、次の簡単な方法を使用します。

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

nxtScr.comingFrom = @"PreviousScreen"l
[self.navigationController nxtScr animated:YES];
于 2015-11-28T06:55:29.190 に答える
1

デリゲートとセグエなしで作成することを好みます。これは、カスタム init を使用するか、オプションの値を設定することで実行できます。

1.カスタム初期化

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?()
  }
}
于 2019-02-06T09:08:07.677 に答える
-1

より簡単な方法はこちらです。

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

たとえば、それぞれ と という 2 つのクラスがclassAありclassBます。

では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
{
    ...
}

classB次に、2 番目のクラスをにインポートしclassAます。

#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は class のグローバル オブジェクトです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 ファイルを最初のクラスにインポートする必要があります。ただし、最初のクラスの .h ファイルを 2 番目のクラスにインポートする必要はありません。

ブリッジを思い出してください。橋があれば両側通れるはずです。

于 2016-07-07T12:59:33.447 に答える
-7

通知センターを使用して、あるビューから別のビューにデータを渡します。

オブザーバー リスナー パターンが最適です。もう 1 つの回避策は、両方のクラスで同じオブジェクトを作成することです。

クラス 1 にクラス 2 オブジェクトを作成します。渡すデータ オブジェクトにアクセスして設定し、ビュー コントローラーをプッシュします。

于 2013-07-17T10:41:21.293 に答える