Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
90
Help us understand the problem. What is going on with this article?
@fromage-blanc

【Swift4】次の画面にデータを引き継ぐ5つの方法【Xcode】

More than 3 years have passed since last update.

画面A(背景ピンク)のテキストフィールドの値を、画面B(背景ブルー)のそれぞれのテキストフィールドに異なる方法で受け渡すサンプルアプリを作ってみます。
v5.pngv7.png

プロジェクトの用意

Xcodeにて「Single View Application」 をテンプレに新規プロジェクトを作成します。

ViewController.swift


import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var textField:UITextField!

    // for back
    @IBAction func goBack(_ segue:UIStoryboardSegue) {}

    /* 1 ++++++++++++++ */
    @IBAction func byInstantiateViewController(_ sender:UIButton) {
        let next = storyboard!.instantiateViewController(withIdentifier: "nextView") as? NextViewController
        let _ = next?.view // ** hack code **
        next?.textField1.text = textField.text
        self.present(next!,animated: true, completion: nil)
    }

    /* 2 ++++++++++++++ */
    @IBAction func byInstantiateViewController2(_ sender:UIButton) {
        let next = storyboard!.instantiateViewController(withIdentifier: "nextView") as? NextViewController
        self.present(next!,animated: true, completion: { () in
            next?.textField2.text = self.textField.text
        })
    }

    /* 3 ++++++++++++++ */
    /// セグエによる遷移
    @IBAction func byPerformSegue(_ sender:UIButton) {
        performSegue(withIdentifier: "nextSegue", sender: nil)
    }

    /// セグエ実行前処理
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let next = segue.destination as? NextViewController
        let _ = next?.view
        next?.textField3.text = textField.text
    }

    /* 4 ++++++++++++++ */
    @IBAction func byUserDefaults(_ sender:UIButton) {
        UserDefaults.standard.register(defaults: ["textField4":textField.text ?? ""])
        UserDefaults.standard.set(textField.text,forKey:"textField4")
        UserDefaults.standard.synchronize()

        let next = storyboard!.instantiateViewController(withIdentifier: "nextView") as? NextViewController
        self.present(next!,animated: true, completion: nil)
    }

    /* 5 ++++++++++++++ */
    @IBAction func byPropertyAccess(_ sender:UIButton) {
        let next = storyboard!.instantiateViewController(withIdentifier: "nextView") as? NextViewController
        self.present(next!,animated: true, completion: nil)
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

NextViewController.swift

import UIKit

class NextViewController: UIViewController {

    @IBOutlet weak var textField1:UITextField!
    @IBOutlet weak var textField2:UITextField!
    @IBOutlet weak var textField3:UITextField!
    @IBOutlet weak var textField4:UITextField!
    @IBOutlet weak var textField5:UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

    }

    override func viewWillAppear(_ animated: Bool) {
        /// ローカルストレージ(UserDefaults)から値を取得
        guard let obj = UserDefaults.standard.object(forKey: "textField4") else {
            return
        }
        textField4.text = obj as? String

        /// 遷移元ビューコントローラにアクセスして値をセット
        textField5.text = (presentingViewController as? ViewController)?.textField.text

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

ストーリーボード関連

ViewController

Controlを押しながら部品からコードに向かってドラッグします。
x1.png

NextViewController

同様に、Controlを押しながら部品からコードに向かってドラッグします。
x2.png

セグエ

セグエIDを設定します。今回はnextSegueとしました。
v3.png

カスタムクラス

遷移先のビューコントローラクラスにNextViewControllerを割り当てます。
v4.png

解説

1.遷移先のビューコントローラのインスタンスを取得してプロパティにセット(その1)

ViewController
    let next = storyboard!.instantiateViewController(withIdentifier: "nextView") as? NextViewController
    let _ = next?.view // ** hack code **
    next?.textField1.text = textField.text
    self.present(next!,animated: true, completion: nil)

「1-instantiateViewController」ボタン押下時。instantiateViewController()にて遷移先ビューコントローラのインスタンスを取得してそのプロパティにアクセス。
let _ = next?.view はアウトレット変数(textField1)をインスタンスさせるためのハックコードです。

2.遷移先のビューコントローラのインスタンスを取得してプロパティにセット(その2)

ViewController
    let next = storyboard!.instantiateViewController(withIdentifier: "nextView") as? NextViewController
    self.present(next!,animated: true, completion: { () in
       next?.textField2.text = self.textField.text
    })

「2-instantiateViewController2」ボタン押下時。instantiateViewController()にて遷移先ビューコントローラのインスタンスを取得するとこまでは前項と同じですが、present()のコールバックブロックにてプロパティをセットしています。ハックコードが不要となりますが、テキストフィールドがチラつく感じがちょっと。。。

3.遷移先のビューコントローラのインスタンスを取得してプロパティにセット(その3)

ViewController
   performSegue(withIdentifier: "nextSegue", sender: nil)
ViewController
    /// セグエ実行前処理
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let next = segue.destination as? NextViewController
        let _ = next?.view
        next?.textField3.text = textField.text
    }

「3-performSegue」ボタン押下時。セグエ実行前に遷移先インスタンスを取得する方法。performSegue()は内部にてprepare()をコールしますのでこれをオーバーライド。アウトレット変数対策のハックコードが必要です。

4.ローカルストレージを経由

ViewController
    UserDefaults.standard.register(defaults: ["textField4":textField.text ?? ""])
    UserDefaults.standard.set(textField.text,forKey:"textField4")
    UserDefaults.standard.synchronize()

    let next = storyboard!.instantiateViewController(withIdentifier: "nextView") as? NextViewController
    self.present(next!,animated: true, completion: nil)
NextViewController
    /// ローカルストレージ(UserDefaults)から値を取得
    guard let obj = UserDefaults.standard.object(forKey: "textField4") else {
        return
    }
    textField4.text = obj as? String

「4-UserDefaults」ボタン押下時。ローカルストレージに保存して遷移先でロードする方法。そこまでの永続性は必要ないと思いますが参考までに。。。

5.遷移元のビューコントローラのインスタンスを取得

NextViewController
    /// 遷移元ビューコントローラにアクセスして値をセット
    textField5.text = (presentingViewController as? ViewController)?.textField.text

遷移先から遷移元ビューコントローラのインスタンスにアクセスする方法。UIViewControllerのプロパティ、presentingViewControllerには遷移元ビューコントローラのインスタンスが格納されています。ただし、格納タイミングはビュースタック構築後なので、viewDidLoad()内でアクセスしてもnilなので注意が必要です。

90
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
fromage-blanc
楽曲制作(ベリバービリバー/石川ひとみ等)と開発(Webシステム、iPhoneアプリ)を生業にしてます。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
90
Help us understand the problem. What is going on with this article?