iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 23
0
自我挑戰組

30 天了解 Swift 的 Combine系列 第 23

30 天了解 Swift 的 Combine: [23] Combine Log in 實作

Demo project: link

在學習了 22 天了之後, 是時候實作了, 這次我們要做使用者登入的機制, 功能如下:

  1. 賬號與密碼必須同時超過 3 碼, 才能登入
  2. 可記住賬號

程式碼

class ViewController: UIViewController {
    // 1
    @IBOutlet weak var accountTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var autoLoginSwitch: UISwitch!
    @IBOutlet weak var loginButton: UIButton!
    
    // 2
    var set = Set<AnyCancellable>()
    
    // 3
    let setting = Setting()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 4
        let accountPublisher = accountTextField
            .publisher(for: .editingChanged)
            .map(\.text)
            .prepend(setting.keepAccount)
            .replaceNil(with: "")
        let passwordPublisher = passwordTextField
            .publisher(for: .editingChanged)
            .map(\.text)
            .replaceNil(with: "")
        // 5
        Publishers.CombineLatest(accountPublisher, passwordPublisher)
            .map{$0.0.count > 2 && $0.1.count > 2}
            .assign(to: \UIButton.isEnabled, on: loginButton)
            .store(in: &set)
        // 6
        setting.oneTimePublisher
            .map{!$0.isEmpty}
            .assign(to: \.isOn, on: autoLoginSwitch)
        // 7
        setting.oneTimePublisher
            .map{$0 as String?}
            .assign(to: \.text, on: accountTextField)
        // 8
        autoLoginSwitch
            .publisher(for: .valueChanged)
            .map(\.isOn)
            .prepend(autoLoginSwitch.isOn)
            .combineLatest(accountPublisher.debounce(for: .seconds(0.5), scheduler: RunLoop.main))
            .map{ $0.0 ? $0.1 : ""}
            .receive(on: RunLoop.main)
            .assign(to: \Setting.keepAccount, on: setting).store(in: &set)
        }
}
  1. 所有的 UI 使用 @IBOutlet 的方式取得.
  2. 保存AnyCancellable, 因為這次範例不需要主動取消, 故用集合.
  3. Model 抽象嫁接, 目標是 UserDefault, 請看 code
  4. 如果沒有從 step.5 分離會導致 Compiler 超時
  5. 因為需要在每個改動時取得上游通知, 所以使用 CombineLatest
  6. 這部分其實可以用單純的 switch.isOn = !setting.account.isEmpty
  7. 這部分其實可以用單純的 textField.text = setting.account
  8. 由於 CombineLatest 的特性, SwitchPublisher 必須 prepend, 讓使用者可以不用觸發 switch 就能夠更新 Modal

上一篇
30 天了解 Swift 的 Combine: [22] WWDC demo 解讀
下一篇
30 天了解 Swift 的 Combine: [24] 分享 SPM 與 CombineHelper
系列文
30 天了解 Swift 的 Combine30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言