如何在Swift中获取UIStoryboard数组?
我发现我的故事板变得非常复杂,并决定将它分成不同的故事板。但是我希望能够*地实例化一个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
任何地方。有没有解决这个问题的方法?我知道我可能有一个静态的故事板名称列表,但这样,扩展名将不会是动态的,并且与项目无关。
任何人都可以帮忙吗?谢谢。
编辑:
组合来自here的accepted 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
文件夹中。我知道,这不是运行时间最有效的代码。但现在,这很容易理解,我可以忍受这一点。 :)感谢大家谁帮助!
故事板通常设置为本地化,因此您应该在您的软件包资源目录的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的未来版本中更改。
哦,哇,这太棒了!让我试着将其纳入代码中,并会再次回复您。谢谢! –
“请注意,编译后的故事板后缀尤其不是SDK的文档部分,因此它可能会在iOS/Xcode的未来版本中发生变化。” - >没关系,我可以添加一些解决方法和预防措施,现在我知道'NSBundle'是如何工作的。 –
即使它发生变化,它也不会影响到您,直到您使用较新的iOS部署目标重建您的应用程序。 –
不要这样做。
取而代之的是,根据需要使用故事板参考材料以适应不同的故事板。
这也可以做到。但我有点不喜欢赛格。如果观看控制器已经很丰富(因此为什么我想将它们分离到不同的故事板),Segue会混乱故事板。但它仍然会混乱。我们只是说我想尝试不同的编程方法,以找出最适合我的东西。 :) –
在你的情况下,如果你把故事板放在一起,也许它会更干净。并以编程方式创建所有视图控制器。
这对我来说是个好主意。不适用于继续我的工作的开发人员。 ( –
)教他们如何做到这一点,它并不复杂,一个好的iOS开发者应该能够同时做到这两点。(\ w storyboard and programmatically) – Mikasa
这并不复杂,但不是太高产,特别是在视觉设计可以快速操纵设计的人是首先创建设计的人,其他人仍然需要深入代码并搜索控制该标签的y位置的那一行代码里面的那个单元格里面那个tableview里面的那个容器里面那个页面控件里面的控件... –
您可以在此行self.navigationController中获取storyboards viewcontroller的导航堆栈数组 –
。viewControllers你可以得到你的viewcontrollers的导航数组 –
@JitendraModi你的意思是'self.navigationController.viewControllers'?我的意思是我想从UIStoryboard实例化新的viewController,而不是访问导航堆栈数组上已经存在的viewControllers。 –