【在 iOS 开发路上的大小事-Day06】透过 Delegate 来传值

前情提要

一般我们在做传值动作的时候,会有好几种方式可以做,像是用 Segue、Closure、Delegate、Global Variable、Notification 等方式,每种都有不同的应用场景,所以就依情况来使用~

前面已经有介绍过 GlobalVariable、Segue、Closure 传值了

今天要介绍的是 Delegate 传值

我们要做的一样是将第一个画面上的 TextField 里的值传到第二个画面的 TextView 上
画面设计这里就不示范了,大家就自己设计就可以了
Delegate 传值也是在实作上很常用到的传值方法之一
话不多说,就马上进入实作环节!

实作环节

首先,我们需要先设计一个协定 (Procotol) 来让 Controller 遵守,我们需要这个 Protocol 来帮我们获取 FirstVC 上 TextField 的值,所以我们先定义一个 Protocol 叫做 FetchTextDelegate,然後在 Protocol 内定义一个 Method,叫做 fetchTextFromTextField

我们在 fetchTextFromTextField 这个 Method 里面宣告了一个变数 text,型别为 String,用来接收在 FirstVC 上 TextField 的值

protocol FetchTextDelegate {
    func fetchTextFromTextField(_ text: String)
}

接着在 FirstVC 里宣告一个变数 delegate,型别为刚刚设计的 Protocol,FetchTextDelegate

var delegate: FetchTextDelegate?

接着在跳页 Button 的 IBAction 里,将 delegate 委任给 SecondVC 来执行
再呼叫先前在 Protocol 里定义好的 fetchTextFromTextField 这个方法 ,让他来取得 TextField 的值,但是用原生 navigationController.pushViewController 来写的话,在执行跳页的时候,会出现 Optional,导致 Crash,後面会来解释如何解决

@IBAction func pushToSecondVC(_ sender: UIButton) {
    let controller = SecondVC(nibName: "SecondVC", bundle: nil)
    self.navigationController?.pushViewController(controller, animated: true, completion: {
        self.delegate = controller
        self.delegate?.fetchTextFromTextField(self.textField.text!)
    })
}

接着让 SeocndVC 来遵守 FetchTextDelegate 这个 Protocol,看是要写在 class 後面,还是用 extension 写都可以,这边我用 extension 来写

// 让 SecondVC 遵守 FetchTextDelegate 这个 Protocol
extension SecondVC: FetchTextDelegate {
    func fetchTextFromTextField(_ text: String) {
        textView.text = text
    }
}

先前在定义 fetchTextFromTextField 这个 Method 时,将 text 这个变数传了进去,这边则是让 TextView 的值等於 text 的值,而这里 text 的值就是从 FirstVC 的 TextField 取得的值

然後再来说为什麽用原生的 navigationController.pushViewController 来跳页的话,会出现 Optional 错误,导致 App Crash

因为在执行跳页的时候,SecondVC 画面还尚未载入完成,所以找不到 textView 这个元件,所以才会导致 Crash,所以必须来改写 navigationController.pushViewController,这边是直接用网路上找到的写法来解决 (参考2)

import UIKit

extension UINavigationController {
    
    // push with completion handler
    public func pushViewController(_ viewController: UIViewController, animated: Bool, completion: @escaping () -> Void) {
        pushViewController(viewController, animated: animated)
        guard animated, let coordinator = transitionCoordinator else {
            DispatchQueue.main.async { completion() }
            return
        }
        coordinator.animate(alongsideTransition: nil) { _ in completion() }
    }
    
    // pop with completion handler
    func popViewController(animated: Bool, completion: @escaping () -> Void) {
        popViewController(animated: animated)
        guard animated, let coordinator = transitionCoordinator else {
            DispatchQueue.main.async { completion() }
            return
        }
        coordinator.animate(alongsideTransition: nil) { _ in completion() }
    }
}

成果


本篇的范例程序码:GitHub

参考资料

  1. https://reurl.cc/qg4o3g
  2. https://gist.github.com/matsuda/3b06eb3d3081b059035fc80d4b677c78

<<:  [火锅吃到饱-5] 北泽寿喜烧 - 台中大里店

>>:  Day4 安装Vue

连续 30 天 玩玩看 ProtoPie - Day 18

接下来要玩 Scale ,讲者提供一个最简单的例子。 左边的方块,Y 值改变的时候,右边的方块的 S...

Day19-"字串练习-2"

利用strcpy()将a字串里的文字复制到b字串,并将b的结果印出。 . . . . . #inc...

课堂笔记 - 物联网概论(3.5)

网路层(2) 3.zigbee ZigBee是一个短距离的通讯由ZigBee联盟所制定的一个无线传...

Vue Slot 的插槽基本用法

脑子就像手机充电一样,充太饱也不会让手机变快,充不够就後继无力。 今天要介绍的是据说及将会在 Vu...

[Day 27] - 新手也能懂的Arduino! – (4)如何看懂电路图Part.2

17King 制造中,订阅一下吧(*´∀`)~♥ 今日影片长度:07 分 20 秒 本集重点条列: ...