正反向傳值的實際應用

春麗 S.T.E.M.
7 min readOct 2, 2023

--

目錄

⦿ 登入註冊流程
⦿ 程式碼
⦿ 正向傳值
⦿ 反向傳值
⦿ 改進方向

登入註冊流程

先看到如下:

如果我們有一個可以選取登入 / 註冊的首頁,分別進到登入、註冊的頁面,通常在管理頁面時,會使用 Navigation Controller 來管理你的跳轉流程,如此一來,從 Button 拉 Segue Show 下一個頁面後,當你想要回上一頁的時候,左上角就會有一個回前頁的預設按鈕,你就不需要自己寫回前頁的 Function,例如 Dismiss,當然,如果前方的頁面有 Embed in Navigation Controller 的話,我們會使用 pushViewControllerpopToViewController跳轉前頁。

所以有沒有 Embed in Navigation Controller,我們在之前學過拉 Segue 時用 show 跟用 present modally 的不同,有 Embed 的 show 等同於 present modally 的 full screen,而不是以 sheet 的方式呈現,當然以 sheet 的方式,在回前一頁則是相對方便。

今天若要做正反向傳值,以 UI 來說,正向傳值就是將當前頁面的資料帶到下一個頁面去,當然如果下一個頁面仍不是你需要呈現資料的頁面,我們還需再傳下去;而反向傳值則是在後續頁面的操作,影響了前面頁面,在這裡,我們希望實際註冊過的人,也就是跳出註冊成功頁面後,希望在登入時浮現一個重傳驗證信的按鈕,在此之前則是隱藏的。

下面我們就來實際操作。

繼續閱讀|回目錄

程式碼

頁面是這樣安排的。

 ViewController => LoginViewController    => ViewController
=> RegisterViewController => WelcomeViewController

正向傳值

LoginViewController 原先有一個 Resend Button,預設 isEnabled = false 或 isHidden = true,而註冊時,直到 WelcomeViewController 出現後,才用反向傳值給 ViewController,這是因為讓 WelcomeViewController 回前頁時,不再經過 RegisterViewController。

再來,這個值要從 ViewController 帶到 LoginViewController,即正向傳值,所以在 ViewController 中:

var resendVerifyLabelEnabled = false            // 能否重傳驗證信

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? LoginViewController {
vc.resendVerifyLabelEnable = resendVerifyLabelEnabled
}
}

反向傳值

用 Delegation Pattern 傳值,我們會這樣寫:

protocol WelcomeViewControllerDelegate: AnyObject {
func sendToMainPage(state: Bool)
}

希望將這個 Resend state 傳到 MainPage,即是 ViewController,所以在 ViewController 中遵循了這個 Delegate 會實作這個 Function,如下:

extension ViewController: WelcomeViewControllerDelegate {

func sendToMainPage(state: Bool) {
resendVerifyLabelEnabled = state
}
}

將自己的屬性改為這個 state,接著再傳到 LoginViewController,就是上面正向傳值的程式碼。

那麼,反向傳值在 WelcomeViewController 中:

private(set) var resendVerifyLabelState = false
weak var delegate: WelcomeViewControllerDelegate?

@objc private func unwindMainPage() {
guard let vc = self.navigationController?.viewControllers.first as? ViewController else { return }
// vc.resendVerifyLabelEnabled.toggle()
// vc.resendVerifyLabelEnabled = !resendVerifyLabelState

delegate = vc
delegate?.sendToMainPage(state: !resendVerifyLabelState)

self.navigationController?.popToRootViewController(animated: true)
}

須有一個 state,並且需要一個 delegate,當回到 Main Page 時,必須將當前的值傳到 Main Page(ViewController),以 Main Page 為 delegate 時,就可透過 delegate 去呼叫 sendToMainPage 這個 Function,由於在 ViewController 中我們已實作這個 Function 了,即是在回到 ViewController 時,這個值已順利傳過去 ViewController 的屬性。

雖然也可以直接對 VC 的屬性 toggle,但我們還是盡量不要直接操作屬性,所以用 vc.resendVerifyLabelEnabled = !resendVerifyLabelState 是比較恰當的,而 delegate 就像是利用 Function 將兩個屬性橋接起來。

結果如下:

繼續閱讀|回目錄

改進方向

雖然在 Register 的地方是打 API 成功後才會跳轉到 WelcomeViewController,但這只有在 APP 第一次正確操作時,才會決定 Resend 這個 Button 是否存在,即是說,下一次我想要 Resend Verification Link 時是沒有辦法的。

今天是這樣,當你 Register 時,伺服器會發驗證信到你註冊的 Email(等同帳號),但是這個驗證信的連結會有時效性,比方十五分鐘,十五分鐘後必須重新發驗證信,不得用原來的連結,所以這個 Resend 應該還是交由後端來判斷成功與否,而不是先過一層是否要給使用者 Resend,即是長存會是比較恰當的做法。

等到打 API 後,確定這個帳號是存在,並且前一封信時效性還沒過(通常會直接覆蓋),否則回傳錯誤,例如該帳號不存在⋯⋯。

這次就分享到這,感謝您的閱讀。

繼續閱讀|回目錄

附上 GitHub:

--

--

春麗 S.T.E.M.
春麗 S.T.E.M.

Written by 春麗 S.T.E.M.

Do not go gentle into that good night, Old age should burn and rave at close of day; Rage, rage, against the dying of the light.

No responses yet