4
6

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 5 years have passed since last update.

iOSアプリ開発入門#2 ~UINavigationController~

Last updated at Posted at 2019-03-02

目的

  • よく使うであろうUINavigationControllerを使用したアプリをStoryboardありとなしでサクッと作れるようになる
  • ありなしの両方を試すことで、Storyboardが何をやっているのかなんとなくイメージできるようになる

Step1. 爆速でUINavigationController管理化

前回のコード をベースに作業。
今回もひとまずStoryboardではなくコード側で実装してみる

1.1. AppDelegateの修正

まずはAppDelegateを以下のように修正

AppDelegate.swift
--- a/PracticeApp/AppDelegate.swift
+++ b/PracticeApp/AppDelegate.swift
@@ -16,6 +16,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
 
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
         // Override point for customization after application launch.
+        let vc: ViewController = window?.rootViewController as! ViewController
+        let navc: UINavigationController = UINavigationController(rootViewController: vc)
+        window?.rootViewController = navc
+
         return true
     }

ポイントとしては

  • AppDelegateのwindowはStoryboardを利用している場合、didFinishLaunchingWithOptions内部ではすでに諸々の初期化が済んでいるため、rootViewControllerはStoryboardで設定したViewControllerになっている
  • 新たにUINavigationControllerをコンストラクトし、これをwindowのrootViewControllerに差し替えるとともに、もとのViewControllerをUINavigationController側のrootViewControllerに付け替える(linked listにおける挿入処理のイメージ)
  • なお、素直にViewController()でコンストラクトすると、Storyboard上の設定が反映されない

もちろん、こんな妙な処理にしなくても、ViewControllerの初期化処理内でちゃんと表示系を実装してやればそれでいいのだが、あくまでStoryboardとソースコードとの関連を知るのが目的なので。

1.2. ViewControllerも一応修正

また、ViewController側もトップにそれっぽいタイトルを表示してみる

ViewController.swift
--- a/PracticeApp/ViewController.swift
+++ b/PracticeApp/ViewController.swift
@@ -23,6 +23,8 @@ class ViewController:
 
     override func viewDidLoad() {
         super.viewDidLoad()
+
+       self.title = "フルーツ"
     }
 
     // UITableViewDataSource

1.3. 起動

Runすると、一応それっぽくなる
スクリーンショット 2019-03-02 13.36.01.png

Step2. BarButtonItem追加+画面遷移(スタック)

UINavigationControllerの機能だけでとりあえず画面遷移させてみる。
基本的な考え方としては

  • UINavigationController管理下のUIViewControllerからNavigationController関連機能にアクセスする際は、インスタンス変数「navigationItem」、「navigationController」を使用する
    • (UINavigationControllerの使用如何に関わらず、navigationItemやnavigationControllerといったpropertyがあるのはいかがなものかと思わなくもない)
  • 画面が次に進む、前に戻るという挙動は、UINavigationControllerが管理するStackにpushする、popするという概念に対応づけられる

2.1. ViewControllerの修正

というわけで、以下のようにViewControllerを修正する。

ViewController.swift
--- a/PracticeApp/ViewController.swift
+++ b/PracticeApp/ViewController.swift
@@ -21,10 +21,20 @@ class ViewController:
         ("ぶどう", "Grape"),
     ]
 
+    private var stackIndex = 0
+
     override func viewDidLoad() {
         super.viewDidLoad()
 
-       self.title = "フルーツ"
+        self.title = "フルーツ index:\(stackIndex)"
+
+        self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back",
+                                                                style: .plain,
+                                                                target: nil,
+                                                                action: nil)
+        self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add,
+                                                                 target: self,
+                                                                 action: #selector(onAddClick))
     }
 
     // UITableViewDataSource
@@ -46,5 +56,12 @@ class ViewController:
         cell.detailTextLabel?.text = data[rowIndex].1
         return cell
     }
+
+    @objc
+    func onAddClick() {
+        let vc: ViewController = self.storyboard!.instantiateInitialViewController() as! ViewController
+        vc.stackIndex = self.stackIndex + 1
+        self.navigationController?.pushViewController(vc, animated: true)
+    }
 }

ポイントとしては

  • navigationControllerのpushViewControllerでpush操作
  • popはデフォルトでbackBarButtonItemにバインドされている
  • 子ViewControllerはこのクラス自身であり、Storyboard側で初期化を行なっているため、UIStoryboardのinstantiateInitialViewControllerで取得している

2.2. 起動

Runすると、「+」押下で同じ画面が次々にStackされていくのがわかる。

スクリーンショット 2019-03-02 13.55.39.png

Step3. Storyboardを使ってみる

今回もコードで地道に書いているところをStoryboardにお任せする流れ

3.1. UINavigationControllerの追加

例によってStoryboard右上のボタンからコンポネント追加
スクリーンショット 2019-03-02 14.09.53.png

ここから追加すると、RootViewControllerが紐づいた状態で配置されてとても邪魔。
爆速で消しにかかる。
スクリーンショット_2019-03-02_14_10_03.png

また、EntrypointをUINavigationController側に変更する
スクリーンショット_2019-03-02_14_10_41.png

UINavigationControllerのrootViewControllerとして既存のViewControllerをバインドする
スクリーンショット_2019-03-02_14_10_56.png

Storyboard経由でViewControllerを取得するために、identityも忘れずに設定しておく
スクリーンショット_2019-03-02_14_11_08.png

3.2. コード修正

UI操作はこれだけ。
これによって以下のコードが削減できる。

AppDelegate.swift
--- a/PracticeApp/AppDelegate.swift
+++ b/PracticeApp/AppDelegate.swift
@@ -16,10 +16,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
 
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
         // Override point for customization after application launch.
-        let vc: ViewController = window?.rootViewController as! ViewController
-        let navc: UINavigationController = UINavigationController(rootViewController: vc)
-        window?.rootViewController = navc
-
         return true
     }
ViewController.swift
--- a/PracticeApp/ViewController.swift
+++ b/PracticeApp/ViewController.swift
@@ -59,7 +59,7 @@ class ViewController:

     @objc
     func onAddClick() {
-        let vc: ViewController = self.storyboard!.instantiateInitialViewController() as! ViewController
+        let vc: ViewController = self.storyboard!.instantiateViewController(
+            withIdentifier: "MainViewController") as! ViewController
         vc.stackIndex = self.stackIndex + 1
         self.navigationController?.pushViewController(vc, animated: true)
     }

ポイントとしては

  • Storyboardからinitialと異なるViewControllerを取得するにはidentityの設定が必要

3.3. 起動

Runすると同じ動き
スクリーンショット 2019-03-02 14.40.09.png

4. まとめ

最終的に以下のようなコードになるはず

ViewController.swift
import UIKit

class ViewController:
    UIViewController,
    UITableViewDelegate,
    UITableViewDataSource
{
    @IBOutlet weak var tableView: UITableView!

    private let data: [(String,String)] = [
        ("りんご", "Apple"),
        ("みかん", "Orange"),
        ("ぶどう", "Grape"),
    ]

    private var stackIndex = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = "フルーツ index:\(stackIndex)"

        self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back",
                                                                style: .plain,
                                                                target: nil,
                                                                action: nil)
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add,
                                                                 target: self,
                                                                 action: #selector(onAddClick))
    }

    // UITableViewDataSource

    func tableView(_ tableView: UITableView,
                   numberOfRowsInSection section: Int) -> Int
    {
        return data.count
    }

    func tableView(_ tableView: UITableView,
                   cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell",
                                                                  for: indexPath)

        let rowIndex: Int = indexPath[1]
        cell.textLabel?.text = data[rowIndex].0
        cell.detailTextLabel?.text = data[rowIndex].1
        return cell
    }

    @objc
    func onAddClick() {
        let vc: ViewController = self.storyboard!.instantiateViewController(
            withIdentifier: "MainViewController") as! ViewController
        vc.stackIndex = self.stackIndex + 1
        self.navigationController?.pushViewController(vc, animated: true)
    }
}
4
6
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
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?