你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 如何在Xcode 8中更好地使用StoryBoard

如何在Xcode 8中更好地使用StoryBoard

編輯:IOS開發基礎

1-fMnF6nAbL2ebDZoy4442jA.png

  • 原文:Xcode: A Better Way to Deal with Storyboards

  • 譯者:CocoaChina-蝦丸


蘋果在Xcode 8中為 Interface Builder 的界面做了非常偉大的改善,Size Classes 變得更加直觀,StoryBoard的使用也變得更加的便利,還有一個完整度驚人的 Interface Builder 預覽界面,這對於那些對 interface Builder 的使用猶豫不決的人來說, 可能成為巨大的沖擊。

在另一方面, 許多開發者在使用Interface Builder的時候仍然有一些麻煩, 尤其是在構建一個巨大的包含復雜導航的多屏幕應用的時候。

在這篇文章裡, 我將分享給你一些處理項目裡面的 StroyBoards 和 Nibs 的好建議,如果你還沒有用過Interface Builder, 或者你正打算使用這個工具,那麼這些建議可能對你很有用。

1. 如果是團隊協作開發, 請為每一個屏幕使用一個單獨的 StoryBoard,如果你是獨立工作, 這依舊是一個好的習慣。

你在項目裡是不是有一個類似於這樣的main.storyboard?

323.png

從設計師的角度來看這非常棒: 你可以很容易的看到完整的用戶界面和導航流, 這正是使用Interface Builder想要達到的目的。

但是這對於開發者來說, 就可能會存在很多問題:

  • 源碼控制: StoryBoard 非常難解決合並時候產生的沖突, 所以單獨的StoryBoard會使你在團隊工作中變得更加輕松。

  • StoryBoard文件會變得非常臃腫和難以駕馭,你有多少次因為點錯而無意中改變了ViewController的約束?

  • 你需要為每一個ViewController分配一個StoryBoard的ID, 這非常容易出錯: 因為你每次使用這個veiwcontroller的時候都要硬編碼這個ID。

如何連接項目裡面的不同的StoryBoard? 這裡有兩種方法:

  • 使用Xcode7中所提供的StoryBoard Reference方案

  • 通過代碼來連接StoryBoard

你可以點擊這裡來閱讀關於第一種方法的更多的內容。

我將要介紹第二種方法, 因為它在復雜的項目中非常的常見。

2. StoryBoard文件與相關的ViewController subclass使用相同的名稱。

這將簡化命名的約定, 並且提供給你一些與第三條建議相關的好處。

3. 在UIViewController subclass中初始化StoryBoard.

在初始化StoryBoard的Base ViewController的代碼中, 我經常看到下面這樣的代碼:

let storyboard = UIStoryboard(name: “Main”, bundle: nil)
let homeViewController = storyboard.instantiateViewController(withIdentifier: “HomeViewController”)

這看起來一點都不清晰: 你需要知道這個StoryBoard的名字, 還需要提供這個ViewController在StoryBoard中的ID, 而且你在創建HomeViewController時, 每次都要使用這種方式。

這有一個更好的方式讓你用代碼在ViewController中使用類方法來初始化它和它所在的StoryBoard:

class HomeViewController: UIViewController {
     static func storyboardInstance() -> HomeViewController? { 
         let storyboard = UIStoryboard(name: String.className(self), 
                                       bundle: nil) return 
         storyboard.instantiateInitialViewController() as?   
                                                 HomeViewController 
     }
}

如果你按照之前的建議來操作, 你就可以避免硬編碼 StoryBoard 的名稱和實體類的名稱.

let StoryBoard = UIStoryBoard(name: String.className(self), bundle: nil)

確保你的StoryBoard的名稱和實體類的名稱完全相同,否則,當視圖引用這個StoryBoard時, 應用程序會崩潰.

這使你代碼的可讀性更高, 而且可以降低出錯率:

class HomeViewController: UIViewController {
     static func StoryBoardInstance() -> HomeViewController? { 
         let StoryBoard = UIStoryBoard(name: String.className(self), 
                                       bundle: nil) return 
         StoryBoard.instantiateInitialViewController() as?   
                                                 HomeViewController 
     }
}

如果你想通過 instantiateInitialViewController()來訪問ViewController, 請確保你在Interface Builder中設置這個ViewController為initialViewController . 如果你在相同的StoryBoard中有多個ViewController, 那麼你需要使用instantiateViewController(withIdentifier: _ )

初始化這個ViewController的時候僅需要這一句代碼:

let homeViewController = HomeViewController.StoryBoardInstance()

區別很明顯吧!

你也可是使用類似的方法從nib中初始化view:

class LoginView: UIView {

     static func nibInstance() -> LoginView? {
        if let loginView =  
              Bundle.mainBundle.loadNibNamed(String.className(self),
                               owner: nil, options: nil)?.first as? 
                               LoginView { 
              return loginView
        } 
        return nil 
     }
}

4. 不要讓你的項目加載太多StoryBoard segue.

如果你遵循了第一個建議,就不會產生這樣的問題。但即使單個StoryBoard中有多個ViewController,使用segue在ViewController之間進行導航也可能也不是個好主意:

你需要為每一個segue命名, 這就很容易出錯,畢竟使用硬編碼的字符串名稱始終不是一個好的編程習慣。

當你為segue添加少量 “if/else” 或 “switch” 語法的時候, PrepareForSegue方法將會變得丑陋而且不易讀。

替代方案是什麼呢?當我們按下導航到下一個ViewController的按鈕的時候, 需要為這個按鈕添加一個IBAction, 還有初始化這個ViewController的代碼. 如果你采用了第三條建議, 那麼它實際上就只有一行代碼.

@IBAction func didTapHomeButton(_ sender: AnyObject) {
    if let nextViewController =    
                     NextViewController.storyboardInstance() {

   // initialize all your class properties
   // homeViewController.property1 = … 
   // homeViewController.property2 = … 

   // either push or present the nextViewController,
   // depending on your navigation structure 

   // present present(nextViewController, animated: true, 
      completion: nil) 

   // or push  
      navigationController?.pushViewController(nextViewController, 
      animated: true)
   }
}

5. 神秘的Unwind segue.

有的時候我們需要讓用戶回到前一個屏幕。

這裡存在另外一個常見的錯誤:使用一個新的segue導航到前面的ViewController,這將創建一個相同實例的ViewController, 它會加入到視圖棧中, 而不是釋放當前處於最頂層的ViewController

從iOS7開始, Interface Builder 提供給你了 “unwind” 導航棧的方案.

39.png

StoryBoard 裡的 Exit outlet

Unwind segue允許你返回到之前任意位置的屏幕,這聽起來很簡單,但是實際上它還需要一些會讓開發者迷惑的額外操作:

  • 通常當你為一個按鈕創建一個outlet事件的時候, Interface Builder 將會為你創建對應的代碼。在這個時候, 按住”control”從按鈕拖動到“Exit” 上面的時候, 對應的代碼就會出現在你的項目裡。

  • 通常當你為一個按鈕創建一個outlet事件的時候, 它會為你的按鈕在對應的類中做關聯。如果是用 Unwind Segues, 你還需要在目標ViewController中編寫代碼。

  • prepareForUnwind 方法有 prepareForSegue 方法的全部缺陷. (請參考前面的說明)

那更簡單的方式是什麼樣子的呢?

那麼我們用代碼簡單的實現一下: 並不用給你的按鈕創建一個”Unwind segue”相關的方法, 而是創建一個常規的方法來實現dismissViewController或者popViewController (請參考你自己的導航結構):

@IBAction func didTapBackButton(_ sender: AnyObject) { 

// if you use navigation controller, just pop ViewController:
  
      if let nvc = navigationController {   
          nvc.popViewController(animated: true)
      } else { 
// otherwise, dismiss it
      dismiss(animated: true, completion: nil)  
   }
}

這就是今天的全部內容.我希望你能發現一些對你有用的東西. 如果你有任何評論、問題,或需要修正的內容, 隨時和我聯系。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved