翻譯自 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 (公開課程), 我們在這種方式的基礎上,進一步建立了一種類型安全的觀察這。