翻译 Swift Tip Notifications

774 阅读1分钟

翻译自 Swift Tip: Notifications · objc.io

Episode 107 Swift Talk 系列文章中 有一篇重构很大的 view controllers,我们 将代码从view controller 移动到一个子 view controller。利用生成的子view controller 处理键盘通知。

在本周的Tips中,我们将展示如何分解代码。

在多个地方通过通知监听键盘事件,每个监听回调的方法中都会手动获取属性,比如:

@objc func keyboardChanged(notification: NSNotification) {
  guard let userInfo = notification.userInfo,
        let frameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue else { return }
  let keyboardScreenFrame = frameValue.cgRectValue
  // …
}

为了节约时间避免一遍遍写重复的获取代码,我们可以写一个包含所有属性的结构体I:

struct KeyboardInfo {
    var animationCurve: UIView.AnimationCurve
    var animationDuration: Double
    var isLocal: Bool
    var frameBegin: CGRect
    var frameEnd: CGRect
}

现在我们可以写一个初始化方法,在这个方法中根据notification的数据组装KeyboardInfo结构体:

extension KeyboardInfo {
    init?(_ notification: Notification) {
        guard notification.name == UIResponder.keyboardWillShowNotification || notification.name == UIResponder.keyboardWillChangeFrameNotification else { return nil }
        let u = notification.userInfo!

        animationCurve = UIView.AnimationCurve(rawValue: u[UIWindow.keyboardAnimationCurveUserInfoKey] as! Int)!
        animationDuration = u[UIWindow.keyboardAnimationDurationUserInfoKey] as! Double
        isLocal = u[UIWindow.keyboardIsLocalUserInfoKey] as! Bool
        frameBegin = u[UIWindow.keyboardFrameBeginUserInfoKey] as! CGRect
        frameEnd = u[UIWindow.keyboardFrameEndUserInfoKey] as! CGRect
    }
}

在我们的 ::keyboardChanged(notification:):: 方法中, 我们可以使用KeyboardInfo结构体,而不是手动解析userInfo字典中的数据:

@objc func keyboardChanged(notification: NSNotification) {
  guard let payload = KeyboardInfo(notification) else { return }
  let keyboardScreenFrame = payload.frameEnd
  // …
}

这样写的代码更简洁,而且更安全一些 (现在字段只在一个地方读取). 当我们想访问其他属性时, 我们只需要输入payload ,然后它会自动将建议的属性名称补全.

Swift Talk Episode 27 (公开课程), 我们在这种方式的基础上,进一步创建了一种类型安全的观察这。