6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

画面遷移でSegueを利用するメリット(Swift)

Last updated at Posted at 2021-05-15

Xcode-12 Swift-5.3 iOS-14

はじめに

画面遷移で Segue はもうほとんど使ってないというのを聞いたので Segue を使う利点を捻り出してみました:dizzy_face:

(私は特に Segue 推奨派というわけではありません:innocent:

そもそも Storyboard 使わない!という方法もあると思いますが今回はそこにはふれません。

つくるもの

Root -> NavigationController -> First -> Second -> Third

上記のように遷移して値を渡して Third から Root に戻るときにも値を渡す方法を考えてみます。

こんな感じ(遷移時に first とか second の文字列を渡してラベルに表示しています)

segue

Segueを使う場合

Segue を使う場合 storyboard はこんな感じです。

segue

コードは Root がこんな感じになります。

final class RootViewController: UIViewController {

    @IBOutlet private weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = ""
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let nav = segue.destination as? UINavigationController,
           let first = nav.viewControllers.first as? FirstViewController,
           let text = sender as? String {
            first.text = text
        }
    }

    override func canPerformUnwindSegueAction(_ action: Selector, from fromViewController: UIViewController, sender: Any?) -> Bool {
        if fromViewController is ThirdViewController {
            if let text = sender as? String {
                label.text = text
            }
        }
        return true
    }

    @IBAction private func showFirst(_ sender: Any) {
        performSegue(withIdentifier: "showFirst", sender: "root")
    }

    // Unwind Segue
    @IBAction private func backFromThird(segue: UIStoryboardSegue) {
    }
}

Third がこんな感じになります。

final class ThirdViewController: UIViewController {

    var text: String?
    @IBOutlet private weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = text
    }

    @IBAction private func backToRoot(_ sender: Any) {
        performSegue(withIdentifier: "backToRoot", sender: (text ?? "") + ", third")
    }
}
:point_down:その他のコード:point_down:
final class FirstViewController: UIViewController {

    var text: String?
    @IBOutlet private weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = text
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let second = segue.destination as? SecondViewController,
           let text = sender as? String {
            second.text = text
        }
    }

    @IBAction private func showSecond(_ sender: Any) {
        performSegue(withIdentifier: "showSecond", sender: (text ?? "") + ", first")
    }
}

final class SecondViewController: UIViewController {

    var text: String?
    @IBOutlet private weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = text
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let third = segue.destination as? ThirdViewController,
           let text = sender as? String {
            third.text = text
        }
    }

    @IBAction private func showThird(_ sender: Any) {
        performSegue(withIdentifier: "showThird", sender: (text ?? "") + ", second")
    }
}

Segueを使わない場合

Segue を使わない場合 storyboard はこんな感じです。

no_segue

コードは Root がこんな感じになります。

final class RootViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = ""
    }

    @IBAction private func showFirst(_ sender: Any) {
        if let nav = storyboard?.instantiateViewController(withIdentifier: "FirstNavigation") as? UINavigationController,
           let first = nav.viewControllers.first as? FirstViewController {
            first.text = "root"
            nav.modalPresentationStyle = .fullScreen
            present(nav, animated: true)
        }
    }
}

Third がこんな感じになります。

final class ThirdViewController: UIViewController {

    var text: String?
    @IBOutlet private weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = text
    }

    @IBAction private func backToRoot(_ sender: Any) {
        if let root = navigationController?.presentingViewController as? RootViewController {
            root.label.text = (text ?? "") + ", third"
            root.dismiss(animated: true, completion: nil)
        }
    }
}
:point_down:その他のコード:point_down:
final class FirstViewController: UIViewController {

    var text: String?
    @IBOutlet private weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = text
    }

    @IBAction private func showSecond(_ sender: Any) {
        if let second = storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController {
            second.text = (text ?? "") + ", first"
            navigationController?.pushViewController(second, animated: true)
        }
    }
}

final class SecondViewController: UIViewController {

    var text: String?
    @IBOutlet private weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        label.text = text
    }

    @IBAction private func showThird(_ sender: Any) {
        if let third = storyboard?.instantiateViewController(withIdentifier: "ThirdViewController") as? ThirdViewController {
            third.text = (text ?? "") + ", second"
            navigationController?.pushViewController(third, animated: true)
        }
    }
}

比較

2つを比較して Segue のメリットを捻出してみます:muscle:

  1. storyboard を見たときに遷移がわかりやすい
    segue

    no_segue
  2. Unwind Segue が使える
    Unwind Segue を使えば Third から Root に戻るときは Modal か Push か気にする必要がなくなります。

  3. Third から Root に値を渡しやすい
    Segue を利用しない場合、下記のように Root に値を渡すときに Modal か Push かによって処理が大きく変わります。Segue を利用すれば遷移方法に依存せず値を渡すことができます!

    @IBAction private func backToRoot(_ sender: Any) {
        if let root = navigationController?.presentingViewController as? RootViewController {
            root.label.text = (text ?? "") + ", third"
            root.dismiss(animated: true, completion: nil)
        }
    }
    

おわりに

がんばって Segue の利点について書こうと思いましたが1画面からいろいろな画面に遷移する場合はどうしても prepareForSegue が太ってくるのでそこは難点:persevere:

id のタイポ問題とかは R.swift を使えば解決すると思います。

なんか他に利点ないかな:thinking:

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?