サーチ…


Seguesを使用する(データを転送する)

セグを使用して、現在のビューコントローラから次の新しいビューコントローラ(以前のビューコントローラではない)にデータを渡すには、まず関連するストーリーボードに識別子を持つセグを作成します。現在のView ControllerのprepareForSegueメソッドをオーバーライドします。メソッド内で、その識別子によって作成したセグをチェックします。宛先ビューコントローラをキャストし、ダウンキャストビューコントローラのプロパティを設定して、データを渡します。

segueの識別子を設定する:

セグのアトリビュートインスペクタ

Seguesは、プログラマチックに、またはストーリーボードに設定されたボタンアクションイベントを使用して、Ctrl +ドラッグ先のビューコントローラにドラッグして実行できます。必要に応じて、ビューコントローラのセグの識別子を使用してプログラム的にセグを呼び出すことができます:

目標-C

- (void)showDetail {
    [self performSegueWithIdentifier:@"showDetailingSegue" sender:self];        
}

迅速

func showDetail() {
    self.performSegue(withIdentifier: "showDetailingSegue", sender: self)
}

segueペイロードは、 prepareForSegueメソッドのオーバーライドされたバージョンで構成できます。宛先ビューコントローラがロードされる前に、必要なプロパティを設定できます。

目標-C

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

迅速

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetailingSegue" {
        let controller = segue.destinationViewController as! DetailViewController
        controller.isDetailingEnabled = true
    }    
}

DetailViewControllerは2番目のView Controllerの名前で、 isDetailingEnabledはそのView Controllerのパブリック変数です。

このパターンを拡張するために、 DetailViewControllerパブリックメソッドを擬似イニシャライザとして扱い、必要な変数を初期化するのに役立てることができます。これは、 DetailViewControllerに設定する必要がある変数を、ソースコードを読み込むことなく、自己文書化します。それはデフォルトを置くのにも便利な場所です。

目標-C

- (void)initVC:(BOOL *)isDetailingEnabled {
    self.isDetailingEnabled = isDetailingEnabled
}

迅速

func initVC(isDetailingEnabled: Bool) {
    self.isDetailingEnabled = isDetailingEnabled
}

デリゲートパターンを使用する(データを返す)

現在のビューコントローラから以前のビューコントローラにデータを戻すには、デリゲートパターンを使用します。

ここに画像の説明を入力

この例では、Interface BuilderでsegueをshowSecondViewController 、segue識別子をshowSecondViewController設定していることを前提としています。アウトレットとアクションは、次のコードの名前にも接続する必要があります。

ファーストビューコントローラ

First View Controllerのコードは次のとおりです。

迅速

class FirstViewController: UIViewController, DataEnteredDelegate {

    @IBOutlet weak var label: UILabel!
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showSecondViewController", let secondViewController = segue.destinationViewController as? SecondViewController  {
            secondViewController.delegate = self
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    func userDidEnterInformation(info: String) {
        label.text = info
        navigationController?.popViewControllerAnimated(true)
    }
}

目標-C

@interface FirstViewController : UIViewController <DataEnteredDelegate>
@property (weak, nonatomic) IBOutlet UILabel *label;
@end

@implementation FirstViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    SecondViewController *secondViewController = segue.destinationViewController;
    secondViewController.delegate = self;

}
-(void)userDidEnterInformation:(NSString *)info {
    _label.text = info
    [self.navigationController popViewControllerAnimated:YES];
}
@end

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

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

2番目のView Controllerのコードは次のとおりです。

迅速

// 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?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        // call this method on whichever class implements our delegate protocol (the first view controller)
        delegate?.userDidEnterInformation(textField.text ?? "")
    }
}

目標-C

@protocol DataEnteredDelegate <NSObject>
-(void)userDidEnterInformation:(NSString *)info;
@end

@interface SecondViewController : UIViewController 
@property (nonatomic) id <DataEnteredDelegate> delegate;
@property (weak, nonatomic) IBOutlet UITextField *textField;
@end

@implementation SecondViewController
- (void)viewDidLoad {
    [super viewDidLoad];
}

- (IBAction) sendTextBackButton:(id)sender{
    [_delegate userDidEnterInformation:textField.text];
}
@end

protocolはView Controllerクラスの外にあることに注意してください。

セグをするために巻き戻しを使用してデータを後方に渡す

現在のビューコントローラからデスティネーションビューコントローラにデータを "転送"できるようにするsegueとは対照的に、

(VC1) (VC2)

"巻き戻し"を使用すると、反対のことができます。送り先または現在のビューコントローラーからそのプレゼンテーションビューコントローラーにデータを渡します。

(VC1) < - (VC2)

:アンワインドを使用すると、データを最初に渡し、その後に現在のビューコントローラ(VC2)が割り当て解除されることに注意してください。

それを行う方法は次のとおりです:

まず、データを渡すビューコントローラであるプレゼンテーションビューコントローラ(VC1)に次の宣言を追加する必要があります。

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)

重要なのは、接頭辞unwindを使うことです。これは、Xcodeに " unwind "メソッドであることを知らせて、ストーリーボードでもそのオプションを使用できるようにします。

その後、メソッドを実装する必要があります。実際のセグエーとほとんど同じです。

@IBAction func unwindToPresentingViewController(segue:UIStoryboardSegue)
{
    if segue.identifier == "YourCustomIdentifer"
    {
        if let VC2 = segue.sourceViewController as? VC2
        {
            //    Your custom code in here to access VC2 class member
        }

今度は、巻き戻し呼び出しを呼び出す2つのオプションがあります。

  1. :あなたは、「ハードコード」を呼び出すことができますself.performSegueWithIdentifier("YourCustomIdentifier", sender: self)いつでも必要になりますあなたのためのアンワインドを行いますperformSegueWithIdentifier
  2. storyboardを使用してアンワインドメソッドを「終了」オブジェクトにリンクすることができます。巻き戻しメソッドを呼び出すボタンをctrl +ドラッグして「終了」オブジェクトにドラッグします。

ここに画像の説明を入力

あなたは、あなたのカスタム巻き戻し方法を選択するオプションを持っています:

ここに画像の説明を入力

クロージャを使用してデータを渡す(データを返す)

UIViewControllerクラスのさまざまな部分で実装を分割するデリゲートパターンを使用する代わりに、 closuresを使用してデータを前後に渡すことさえできます。あなたがUIStoryboardSegueを使用していると仮定することによって、 prepareForSegueメソッドでは、新しいコントローラを簡単にワンステップでセットアップできます

final class DestinationViewController: UIViewController {
    var onCompletion: ((success: Bool) -> ())?

    @IBAction func someButtonTapped(sender: AnyObject?) {
        onCompletion?(success: true)
    }
}

final class MyViewController: UIViewController {
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    
        guard let destinationController = segue.destinationViewController as? DestinationViewController else { return }
    
        destinationController.onCompletion = { success in
            // this will be executed when `someButtonTapped(_:)` will be called
            print(success)
        }
    }
}

これは使用の例であり、SwiftのObjective-Cブロックの構文は、コードを読みやすくするのはそれほど簡単ではありません

データを渡すコールバッククロージャ(ブロック)の使用

このトピックはiOS開発の古典的な問題であり、その解決策はすでに示した他の例のようにさまざまです。この例では、別の日常的な使用方法をもう1つ表示します:このページのdelegate pattern例をコールバックclosure適用してclosureを使用してデータを渡す方法

このメソッドは、 delegate patternよりも優れています。これは、2つの異なる場所(このページのデリゲートの例、 prepareForSegueuserDidEnterInformation )で設定コードを分割するのではなく、( prepareForSegueでのみ表示します)

2番目のビューコントローラから開始

コールバックの使い方を理解してから、それを書くことができます。これは、コールバックを使用する場所であるため、2番目のビューコントローラから始める理由です:新しいテキスト入力を取得したとき、 コールバックのパラメータをメディア最初のViewControllerにデータを渡すには、コールバックのパラメータを使用していることに気付きました。これは非常に重要です。初心者(私がそうだったように)は常にこれを見落とし、コールバッククロージャを正しく書くために

この場合、コールバックは1つのパラメータしか取らないことがわかります。テキストとその型はString 。最初のビューコントローラからデータを取り込む必要があるため、それを宣言してプロパティにしましょう

私はちょうどすべてのdelegate部分をコメントし、比較のためにそれを保つ

class SecondViewController: UIViewController {

    //weak var delegate: DataEnteredDelegate? = nil
    var callback: ((String?)->())?
    
    @IBOutlet weak var textField: UITextField!

    @IBAction func sendTextBackButton(sender: AnyObject) {
        
        //delegate?.userDidEnterInformation(textField.text!)
        callback?(input.text)
        
        self.navigationController?.popViewControllerAnimated(true)
    }
}

最初のビューコントローラを終了する

あなたがしなければならないことは、コールバッククロージャを渡すことだけです。完了しました。クロージャは、すでに2番目のビューコントローラ

delegate patternと比較してコードをどのように短くするか見てみましょう

//no more DataEnteredDelegate
class FirstViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "showSecondViewController" {
            let secondViewController = segue.destinationViewController as! SecondViewController
            //secondViewController.delegate = self
            secondViewController.callback = { text in self.label.text = text }
        }
    }

    // required method of our custom DataEnteredDelegate protocol
    //func userDidEnterInformation(info: String) {
    //    label.text = info
    //}
}

最後に、あなたの誰かが、最初のビューコントローラーから2番目のビューコントローラーから2番目のビューコントローラーから直接戻ってくることなく、1つの方法でのみデータ(この場合はクロージャー)を渡すだけであることを見て混乱します。コミュニケーションツールと考えていますか?多分あなたは本当にそれを実行し、あなた自身でそれを証明すべきです、私はそれがパラメータだと言うでしょう、それはデータを戻すコールバッククロージャのパラメータです!

プロパティ(データの受け渡し)を割り当てることにより、

次のView Controllerのプロパティをプッシュまたはプレゼンテーションする前に割り当てることによって、データを直接渡すことができます。

class FirstViewController: UIViewController {

    func openSecondViewController() {

        // Here we initialize SecondViewController and set the id property to 492
        let secondViewController = SecondViewController()
        secondViewController.id = 492

        // Once it was assign we now push or present the view controller
        present(secondViewController, animated: true, completion: nil)
    }

}

class SecondViewController: UIViewController {
    
    var id: Int?

    override func viewDidLoad() {
        super.viewDidLoad()

        // Here we unwrapped the id and will get the data from the previous view controller.
        if let id = id {
            print("Id was set: \(id)")
        }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow