簡評:
函數是一個組織在一起語句集合,以執行特定任務。Swift 函數類似于簡單 C 函數以及復雜的 Objective C 語言函數。 它使我們能夠通過函數調用內部的局部和全局參數值。 像其他任何語言一樣 swift 函數也遵循相同的步驟。
Swift 函數包含參數類型和返回類型。
函數提前返回主要的好處是:將每個錯誤處理進行分離,審查代碼時不需要考慮多種復雜異常,我們可以吧注意力集中在也業務邏輯中,調試代碼時可以直接在異常中打斷點。
提前返回
首先來看一下需要改進的代碼示例,我們構建一個筆記應用使用 NotificationCenter API,當筆記內容有變化時 Notification 來通知筆記列表變更,代碼如下:
class NoteListViewController: UIViewController {@objc func handleChangeNotification(_ notification: Notification) {let noteInfo = notification.userInfo?["note"] as? [String : Any]if let id = noteInfo?["id"] as? Int {if let note = database.loadNote(withID: id) {notes[id] = notetableView.reloadData()}}}}
上面的代碼可以很好的工作,但是可讀性差了點。因為這段代碼包含多重縮進和類型轉換。我們來嘗試改進這段代碼。
class NoteListViewController: UIViewController {@objc func handleChangeNotification(_ notification: Notification) {let noteInfo = notification.userInfo?["note"] as? [String : Any]guard let id = noteInfo?["id"] as? Int else {return}guard let note = database.loadNote(withID: id) else {return}notes[id] = notetableView.reloadData()}}
將函數提前返回能夠將功能失敗的情況處理得更加清晰,這不僅提高了可讀性(更少的縮進,更少的嵌套),同時也有利于單元測試。
我們可以進一步改進代碼,將獲取 noteID 和類型轉換的代碼放在 Notification Extension 中,這樣就將 handleChangeNotification 業務邏輯和具體細節分離開來。修改后代碼如下所示:
private extension Notification {var noteID: Int? {let info = userInfo?["note"] as? [String : Any]return info?["id"] as? Int}}class NoteListViewController: UIViewController {@objc func handleChangeNotification(_ notification: Notification) {guard let id = notification.noteID else {return}guard let note = database.loadNote(withID: id) else {return}notes[id] = notetableView.reloadData()}}
這種結構還大大簡化了調試的難度,我們可以直接在每個 guard 中 return 中添加斷點來截獲所有失敗情況,而不需要單步執行所有邏輯。
條件構造
當構造一個對象實例,非常普遍的需求是需要構建哪類對象取決于一系列的條件。
例如,啟動應用程序時顯示哪個 view controller 取決于:
我們對這些條件的的實現可能是一系列的 if 和 else 語句,如下所示:
func showInitialViewController() {if loginManager.isUserLoggedIn {if tutorialManager.isOnboardingCompleted {navigationController.viewControllers = [HomeViewController()]} else {navigationController.viewControllers = [OnboardingViewController()]}} else {navigationController.viewControllers = [LoginViewController()]}}
同樣的提前返回和 guard 語句可以提升代碼可讀性,但是現在這種情況不是處理失敗情況,而是在不同條件下構建不同 view controller。
現在來改進這段代碼,使用輕量級的工程模式,將構造初始界面移動到專門的函數中,該函數返回匹配條件的view controller。如下所示:
func makeInitialViewController() -> UIViewController {guard loginManager.isUserLoggedIn else {return LoginViewController()}guard tutorialManager.isOnboardingCompleted else {return OnboardingViewController()}return HomeViewController()}func showInitialViewController() {let viewController = makeInitialViewController()navigationController.viewControllers = [viewController]}
由于 makeInitialViewController 方法是個純函數(不影響外部狀態,固定輸入能夠得到固定輸出),實際上影響外部狀態的只有一個地方 navigationController.viewControllers = [viewController] ,(在日常開發中狀態如果沒有得到很好的控制很容易引起 bug,所以使用更少狀態和減少對狀態的修改可以一定程度上減少 bug 出現的幾率)。
條件控制
最后我們來看看,函數如何簡化復雜的條件邏輯。我們來構建一個 view controller 來顯示社交應用的評論功能,如果滿足三個條件則運行用戶對評論進行編輯。代碼如下:
class CommentViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()if comment.authorID == user.id {if comment.replies.isEmpty {if !comment.edited {let editButton = UIButton()...view.addSubview(editButton)}}}...}}
這里使用了 3 個 if 嵌套邏輯,每次重新審查代碼都會比較困擾,更具之前的經驗我們可以對代碼進行優化,添加 Comment extension:
extension Comment {func canBeEdited(by user: User) -> Bool {guard authorID == user.id else {return false}guard comment.replies.isEmpty else {return false}return !edited}}class CommentViewController: UIViewController {override func viewDidLoad() {super.viewDidLoad()if comment.canBeEdited(by: user) {let editButton = UIButton()...view.addSubview(editButton)}...}}
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。
新聞熱點
疑難解答