正反向傳值的實際應用
目錄
⦿ 登入註冊流程
⦿ 程式碼
⦿ 正向傳值
⦿ 反向傳值
⦿ 改進方向
登入註冊流程
先看到如下:
如果我們有一個可以選取登入 / 註冊的首頁,分別進到登入、註冊的頁面,通常在管理頁面時,會使用 Navigation Controller 來管理你的跳轉流程,如此一來,從 Button 拉 Segue Show 下一個頁面後,當你想要回上一頁的時候,左上角就會有一個回前頁
的預設按鈕,你就不需要自己寫回前頁的 Function,例如 Dismiss,當然,如果前方的頁面有 Embed in Navigation Controller 的話,我們會使用 pushViewController
跟 popToViewController
來跳轉
或回
前頁。
所以有沒有 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: