2017-06-02 40 views
1

我發現我的故事板變得非常複雜,並決定將它分成不同的故事板。但是我希望能夠自由地實例化一個UIViewController,無論我把視圖控制器放在哪裏。這樣,我就可以將View Controller從Storyboard移動到Storyboard,而無需記住我把View Controller放在哪裏,而且我也不必更新代碼,因爲它們全都使用相同的代碼來實例化具有該名稱的相同View Controller,而不管它駐留在何處。如何在Swift中獲取UIStoryboard數組?

因此,我想是這樣創造的UIViewController的擴展:

extension UIViewController { 

    func instantiate (named: String?, fromStoryboard: String? = nil) -> UIViewController? { 
    guard let named = named else { return nil; } 
    if let sbName = fromStoryboard { 
     let sb = UIStoryboard(name: sbName, bundle: nil); 
     return sb.instantiateViewController(withIdentifier: named); 
    } 
    else { 
     for sb in UIStoryboard.storyboards { 
      if let vc = sb.instantiateViewController(withIdentifier: named) { 
       return vc; 
      } 
     } 
    } 
    return nil; 
} 

的問題是,我無法找到屬性/方法返回故事板的實例列表像.storyboards任何地方。有沒有解決這個問題的方法?我知道我可能有一個靜態的故事板名稱列表,但這樣,擴展名將不會是動態的,並且與項目無關。

任何人都可以幫忙嗎?謝謝。

編輯:

組合來自hereaccepted answer和答案安全實例化視圖 - 控制(並返回零,如果沒有找到),這是我的代碼:

UIStoryboard + Storyboards.swift:

extension UIStoryboard { 

    static var storyboards : [UIStoryboard] { 
     let directory = Bundle.main.resourcePath! + "/Base.lproj" 
     let allResources = try! FileManager.default.contentsOfDirectory(atPath: directory) 
     let storyboardFileNames = allResources.filter({ $0.hasSuffix(".storyboardc")}) 
     let storyboardNames = storyboardFileNames.map({ ($0 as NSString).deletingPathExtension as String }) 
     let storyboardArray = storyboardNames.map({ UIStoryboard(name: $0, bundle: Bundle.main)}) 
     return storyboardArray; 
    } 

    func instantiateViewControllerSafe(withIdentifier identifier: String) -> UIViewController? { 
     if let availableIdentifiers = self.value(forKey: "identifierToNibNameMap") as? [String: Any] { 
      if availableIdentifiers[identifier] != nil { 
       return self.instantiateViewController(withIdentifier: identifier) 
      } 
     } 
     return nil 
    } 

} 

UIViewController + Instantiate.swift:

extension UIViewController { 

    static func instantiate (named: String?, fromStoryboard: String? = nil) -> UIViewController? { 
     guard let named = named else { return nil; } 
     if let sbName = fromStoryboard { 
      let sb = UIStoryboard(name: sbName, bundle: nil); 
      return sb.instantiateViewControllerSafe(withIdentifier: named); 
     } 
     else { 
      for sb in UIStoryboard.storyboards { 
       if let vc = sb.instantiateViewControllerSafe(withIdentifier: named) { 
        return vc; 
       } 
      } 
     } 
     return nil; 
    } 
} 

限制所有故事板文件必須位於Base.lproj文件夾中。我知道,這不是運行時間最有效的代碼。但現在,這很容易理解,我可以忍受這一點。 :)感謝大家誰幫助!

+0

您可以在此行self.navigationController中獲取storyboards viewcontroller的導航堆棧數組 –

+0

。viewControllers你可以得到你的viewcontrollers的導航數組 –

+0

@JitendraModi你的意思是'self.navigationController.viewControllers'?我的意思是我想從UIStoryboard實例化新的viewController,而不是訪問導航堆棧數組上已經存在的viewControllers。 –

回答

1

故事板通常設置爲本地化,因此您應該在您的軟件包資源目錄的Base.lproj子目錄中查找它們。故事板被編譯成擴展名爲.storyboardc的文件,因此您應該查找具有該後綴的文件並將其剝離。

let directory = Bundle.main.resourcePath! + "/Base.lproj" 
let allResources = try! FileManager.default.contentsOfDirectory(atPath: directory) 
let storyboardFileNames = allResources.filter({ $0.hasSuffix(".storyboardc")}) 
let storyboardNames = storyboardFileNames.map({ ($0 as NSString).deletingPathExtension as String }) 
Swift.print(storyboardNames) 

如果已創建特定於設備的故事板(通過添加或~ipad~iphone到故事板的文件名),那麼你還需要脫掉這些後綴和消除重複。

請注意,已編譯的故事板後綴尤其不是SDK的文檔部分,因此它可能會在iOS/Xcode的未來版本中更改。

+0

哦,哇,這太棒了!讓我試着將其納入代碼中,並會再次回覆您。謝謝! –

+0

「請注意,編譯後的故事板後綴尤其不是SDK的文檔部分,因此它可能會在iOS/Xcode的未來版本中發生變化。」 - >沒關係,我可以添加一些解決方法和預防措施,現在我知道'NSBundle'是如何工作的。 –

+1

即使它發生變化,它也不會影響到您,直到您使用較新的iOS部署目標重建您的應用程序。 –

0

不要這樣做。

取而代之的是,根據需要使用故事板參考材料以適應不同的故事板。

+0

這也可以做到。但我有點不喜歡賽格。如果觀看控制器已經很豐富(因此爲什麼我想將它們分離到不同的故事板),Segue會混亂故事板。但它仍然會混亂。我們只是說我想嘗試不同的編程方法,以找出最適合我的東西。 :) –

1

在你的情況下,如果你把故事板放在一起,也許它會更乾淨。並以編程方式創建所有視圖控制器。

+0

這對我來說是個好主意。不適用於繼續我的工作的開發人員。 ( –

+0

)教他們如何做到這一點,它並不複雜,一個好的iOS開發者應該能夠同時做到這兩點。(\ w storyboard and programmatically) – Mikasa

+0

這並不複雜,但不是太高產,特別是在視覺設計可以快速操縱設計的人是首先創建設計的人,其他人仍然需要深入代碼並搜索控制該標籤的y位置的那一行代碼裏面的那個單元格里面那個tableview裏面的那個容器裏面那個頁面控件裏面的控件... –

相關問題