prepareForSegueを渡す方法:オブジェクト


358

マップビュー(rightCalloutAccessoryボタン付き)に多くの注釈があります。ボタンは、これからmapviewへのセグエを実行しますtableviewtableviewどのコールアウトボタンがクリックされたかに応じて(データを保持する)別のオブジェクトを渡します。

例:(完全に構成)

  • annotation1(オースティン)->データobj 1を渡す(オースティンに関連)
  • annotation2(ダラス)->データobj 2を渡す(ダラスに関連)
  • annotation3(ヒューストン)->データobj 3などを渡す...(アイデアがわかります)

どのコールアウトボタンがクリックされたかを検出できます。

私は使用していprepareForSegueます:データobjを宛先に渡しますViewController。この呼び出しで必要なデータobjに追加の引数をとることができないため、同じ効果を達成するためのエレガントな方法(動的データobj)は何ですか?

任意のヒントをいただければ幸いです。


回答:


674

prepareForSegue:メソッドのターゲットビューコントローラーへの参照を取得し、そこに必要なオブジェクトを渡すだけです。ここに例があります...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"YOUR_SEGUE_NAME_HERE"])
    {
        // Get reference to the destination view controller
        YourViewController *vc = [segue destinationViewController];

        // Pass any objects to the view controller here, like...
        [vc setMyObjectHere:object];
    }
}

改訂:performSegueWithIdentifier:sender:メソッドを使用して、選択またはボタンの押下に基づいて、新しいビューへの遷移をアクティブ化することもできます。

たとえば、2つのView Controllerがあるとします。最初のボタンには3つのボタンが含まれ、2番目のボタンには、移行前にこれらのボタンのどれが押されたかを知る必要があります。次のように、メソッドIBActionを使用するコード内でボタンを配線できますperformSegueWithIdentifier:...

// When any of my buttons are pressed, push the next view
- (IBAction)buttonPressed:(id)sender
{
    [self performSegueWithIdentifier:@"MySegue" sender:sender];
}

// This will get called too before the view appears
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"MySegue"]) {

        // Get destination view
        SecondView *vc = [segue destinationViewController];

        // Get button tag number (or do whatever you need to do here, based on your object
        NSInteger tagIndex = [(UIButton *)sender tag];

        // Pass the information to your destination view
        [vc setSelectedButton:tagIndex];
    }
}

編集:私が最初に接続したデモアプリケーションは6年前のものなので、混乱を避けるために削除しました。


ありがとうございますが、[vc setMyObjectHere:object];これを動的に設定したいと思います。つまり、button1のobj1、button2のobj2の問題は、引数を渡すことができないことです。これを回避する方法はありますか?
11

2
私が話していることのダウンロード可能な例で私の投稿を更新しました。
Simon

うまくいきました!本当にありがとう。補足として、prepareForSegue:には、UIButtonの親クラスであるUIControl引数があります(したがって、タグを取得できます):D
chizzle

ストーリーボードセグエなしでナビゲーションコントローラーにプッシュするだけでもprepareForSegueが呼び出されますか?
ザクダンス

これは、私が今まで見た中で最も完全な答えの1つです。優れたコードサンプルは、問題を解決し、ダウンロード可能なサンプルを提供します。私が感銘を受けた!
lewiguez

82

2つのView Controller間にコンパイル時の依存関係を作成しないようにすることが役立つ場合があります。宛先のビューコントローラのタイプを気にせずにそれを行う方法は次のとおりです。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.destinationViewController respondsToSelector:@selector(setMyData:)]) {
        [segue.destinationViewController performSelector:@selector(setMyData:) 
                                              withObject:myData];
    } 
}

したがって、宛先のビューコントローラがパブリックプロパティを宣言している限り、たとえば:

@property (nonatomic, strong) MyData *myData;

上記で説明したように、前のビューコントローラーでこのプロパティを設定できます。


12
これは本当に意見の問題です。私は(まだ)ビューコントローラを「しっかり」制御したくない状況はありませんでしたが、あなたの言っていることに感謝しますが、それは適切な状況では重要かもしれません。
Simon

2
@Simon:ええ、あなたはあなたに最適なアプローチを選ぶだけです。たとえば、現在取り組んでいるアプリでは、同じデータオブジェクトを必要とするビューコントローラーを追加し続けるので、私のアプローチは非常に理にかなっています。セグエだけでそれらを接続でき、適切なデータを取得できることを知ることは非常に便利です。
Macondo2Seattle 2012

10
それは意見の問題ではありません、それは間違っています:)「受け入れられた答えはこれを行う最良の方法ではありません」というフレーズは間違っています。「特定のケースでは、これを行う必要がある...」と表示されているはずです
Fattie

2
私はサイモンの方法を好む。コンパイル時にエラーが表示されるので。たとえば、宛先のビューコントローラでmyDataの宣言を逃した場合、すぐにわかります。しかし、あなたのシナリオでは、あなたのアプローチは良いようです!
Abdurrahman Mubeen Ali 2014

14
宛先のビューコントローラーにを持たせる必要があるため、このアプローチは絶対に依存関係を作成しますsetMyData:。それは依存関係です。セレクターを使用してコンパイルエラーを回避するという事実は、利点ではなく、アプローチの弱点として扱う必要があります。コンパイル時エラーは実行時エラーよりも優先されるべきであるという概念を失った開発者がどれほどいるのか、私には衝撃的です。
2015年

21

Swift 4.2では、私はそのようなことをします:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let yourVC = segue.destination as? YourViewController {
        yourVC.yourData = self.someData
    }
}

: `super.prepare(for:segue、sender:sender)`を呼び出す必要がありますか?
Andrew K

16

私はこのようなセンダークラスを持っています

@class MyEntry;

@interface MySenderEntry : NSObject
@property (strong, nonatomic) MyEntry *entry;
@end

@implementation MySenderEntry
@end

オブジェクトを渡すためにこの送信者クラスを使用しますprepareForSeque:sender:

-(void)didSelectItemAtIndexPath:(NSIndexPath*)indexPath
{
    MySenderEntry *sender = [MySenderEntry new];
    sender.entry = [_entries objectAtIndex:indexPath.row];
    [self performSegueWithIdentifier:SEGUE_IDENTIFIER_SHOW_ENTRY sender:sender];
}

-(void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_SHOW_ENTRY]) {
        NSAssert([sender isKindOfClass:[MySenderEntry class]], @"MySenderEntry");
        MySenderEntry *senderEntry = (MySenderEntry*)sender;
        MyEntry *entry = senderEntry.entry;
        NSParameterAssert(entry);

        [segue destinationViewController].delegate = self;
        [segue destinationViewController].entry = entry;
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_HISTORY]) {
        // ...
        return;
    }

    if ([[segue identifier] isEqualToString:SEGUE_IDENTIFIER_FAVORITE]) {
        // ...
        return;
    }
}

私たちはそれを使用しています prepareForSegueか、それを実装していますか。そして前提はprepareForSegueがそれ自体と呼ばれることです。つまり、次のようなことをする必要ありません[self prepareForSegue]
Honey

15

あるView Controllerから別のView Controllerにデータを渡す方法を学ぼうとしていたときに、この質問に出くわしました。私が学ぶのを助けるために何か視覚的なものが必要なので、この答えはすでにここにいる他の人への補足です。元の質問よりも少し一般的ですが、機能するように調整できます。

この基本的な例は次のように機能します。

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

アイデアは、First View ControllerのテキストフィールドからSecond View Controllerのラベルに文字列を渡すことです。

First View Controller

import UIKit

class FirstViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!

    // This function is called before the segue
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

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

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

}

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

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
    }

}

忘れないでください

  • controlボタンをクリックし、Second View Controllerにドラッグしてセグエを作成します。
  • とのアウトレットを接続UITextFieldUILabelます。
  • 最初と2番目のView ControllerをIBの適切なSwiftファイルに設定します。

ソース

セグエを介してデータを送信する方法(Swift)(YouTubeチュートリアル)

こちらもご覧ください

ビューコントローラー:データの転送と転送(詳細な回答)


5

以下のためにスウィフトは、これを使用します

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    var segueID = segue.identifier

    if(segueID! == "yourSegueName"){

        var yourVC:YourViewController = segue.destinationViewController as YourViewController

        yourVC.objectOnYourVC = setObjectValueHere!

    }
}

4

この操作を簡略化するUIViewControllerにカテゴリを含むライブラリを実装しました。基本的に、セグエを実行しているUIアイテムに関連付けられたNSDictionaryで渡すパラメーターを設定します。手動のセグエでも動作します。

たとえば、次のことができます

[self performSegueWithIdentifier:@"yourIdentifier" parameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

手動でセグエする、またはセグエでボタンを作成して使用する

[button setSegueParameters:@{@"customParam1":customValue1, @"customValue2":customValue2}];

宛先のビューコントローラがキーのキー値コーディングに準拠していない場合、何も起こりません。Key-Valueでも機能します(アンワインドセグエに役立ちます)。https://github.com/stefanomondino/SMQuickSegueで確認してください


2

私の解決策も同様です。

// In destination class: 
var AddressString:String = String()

// In segue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
   if (segue.identifier == "seguetobiddetailpagefromleadbidder")
    {
        let secondViewController = segue.destinationViewController as! BidDetailPage
        secondViewController.AddressString = pr.address as String
    }
}

1

この関数を使用してください。

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let index = CategorytableView.indexPathForSelectedRow
    let indexNumber = index?.row
    let VC = segue.destination as! DestinationViewController
   VC.value = self.data

}

0

私はこのソリューションを使用して、セグエの呼び出しとデータ通信を同じ関数内に維持できるようにしました。

private var segueCompletion : ((UIStoryboardSegue, Any?) -> Void)?

func performSegue(withIdentifier identifier: String, sender: Any?, completion: @escaping (UIStoryboardSegue, Any?) -> Void) {
    self.segueCompletion = completion;
    self.performSegue(withIdentifier: identifier, sender: sender);
    self.segueCompletion = nil
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    self.segueCompletion?(segue, sender)
}

ユースケースは次のようになります。

func showData(id : Int){
    someService.loadSomeData(id: id) {
        data in
        self.performSegue(withIdentifier: "showData", sender: self) {
            storyboard, sender in
            let dataView = storyboard.destination as! DataView
            dataView.data = data
        }
    }
}

これはうまくいくようですが、perform関数とprepare関数が常に同じスレッドで実行されるかどうかは100%わかりません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.