Using Multiple Storyboards in iOS

我的目标是创建一个选项卡式应用程序,然后每个选项卡的视图被构建在单独的故事板中。

Storyboard screenshot

My mainstoryboard is a tab view.

然后我创建了一个带有2个视图控制器的第二故事板(故事板 # 2)。第一个视图控制器(也标记为初始)有一个按钮,并且 segue (模态)到第二个视图。First view controller

我设法通过子类化和覆盖故事板 # 2中的 loadView 来加载视图。 loadView override

这是模拟器输出。

Simulator

When click on the "click me" button, I get a EXC_BAD_ACCESS. The segue does not work, seems like the second storyboard is not being loaded completely.

以前有人试过这么做吗?有一个来自 SkillMaster.net 的 youtube 视频,但是他没有展示是否在第二个故事板下有一个接续。视频在这里: http://youtu.be/D4_twoYvB4M

感谢您的投入和帮助!

Screenshots:

67671 次浏览

苹果的文档说你可能有多个故事板。不幸的是,他们没有详细说明如何做到这一点。正如你已经发现的,Interface Builder 不会帮助你,所以你必须用代码来完成。它的工作原理很像加载 XIBs:

[UIStoryboard storyboardWithName:@”MyNewStoryboard” bundle:myBundle]

话虽如此,如果您不想像您在评论中所说的那样“需要一个大型/臃肿的故事板”,那么 XIBs 确实是一种可行的方法。这种“大”就是好处: 风险投资之间的所有过渡都在一个地方进行。拥有多个故事板确实可以让你通过你的应用程序支持多个不同的和不相关的流程: 例如,一个故事板用于复杂的配置流程,另一个故事板用于主用户流程。

观察家办公室编辑了他的问题,包括答案:

UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"HelpStoryboard" bundle:nil];
UIViewController* initialHelpView = [storyboard instantiateInitialViewController];


initialHelpView.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:initialHelpView animated:YES];

当然,您从哪里调用它是有意义的,因为您可能在内存中有2个故事板和它们的视图堆栈。所以最好是从其他故事板的视图控制器之外调用这段代码。

从我的一个 XIB 文件,我导航到一个更复杂的 GUI 部分,对于这一部分,我使用故事板。因此,我的 XIB 中的一个按钮将导航到故事板。我的代码是:

UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"MyStoryboardIdentifier" bundle:nil];
UIViewController* myStoryBoardInitialViewController = [storyboard instantiateInitialViewController];


[self.navigationController pushViewController:myStoryBoardInitialViewController animated:YES];

这将成功地将 StoryBoard 推送到视图中。上面的代码是从一个按钮“ Touch Up Inside”操作调用的。

这些是我在多个故事板上看到的最好的文章。

Not only does this guy tell you how to create a new storyboard in code, he

  • 在实践中推荐多个故事板(更多的模块化代码)
  • 讨论何时使用 xibs 与情节串连板(xibs 持有视图,情节串连板基于控制器)
  • provides a class for linking storyboards with segues 在 Github 上

请注意,最后一点很重要,因为多个故事板的关键缺点是,您通常不能将它们与续集连接起来,但是 robs 库允许这样做,只需要稍微修改一下

也请参阅讨论的 给你

我发现,如果您在第二个情节串连板中有一个命名的 segue,并且您希望在调用 PerformSegueWithIdentifier 时使用它: 那么您必须在源 ViewController 的“ Identity”选项卡中设置“ Storyboard ID”字段。

例如,如果你给一个名为“ ViewController1”的 VC 加上一个名为“ segue1”的接口,将“ ViewController1”的“ Storyboard ID”设置为任何值(比如“ viewC1”或其他值) ,然后在 ViewController1.m 中可以使用[ self PerformSegueWithIdentifier:@“ segue1”sender: self ]。

I've examined the RBStoryboardLink approach suggested by Rhubarb. 这个实现代替了视图控制器看起来很奇怪的属性。我相信我已经找到了避免这种情况的方法。

导航控制器

导航控制器只能将引用的视图控制器设置为根。这种视图控制器的实现可能如下所示:

@interface ExternNavigationController : UINavigationController


@property (strong, nonatomic) NSString *storyboardName;
@property (strong, nonatomic) NSString *sceneIdentifier;


@end


@implementation ExternNavigationController


- (void)awakeFromNib
{
NSAssert(self.storyboardName, @"storyboardName is required");


UIStoryboard *storyboard = [UIStoryboard storyboardWithName:self.storyboardName bundle:nil];
UIViewController *vc = self.sceneIdentifier
? [storyboard instantiateViewControllerWithIdentifier:self.sceneIdentifier]
: [storyboard instantiateInitialViewController];


self.viewControllers = @[vc];
}


@end

视图控制器

当您想要推动在外部情节串连板中定义的视图控制器时,问题就开始了。复制属性时就是这种情况。取而代之的是,我们可以实现一个自定义的接口,用一个来自外部情节串连板的真实控制器替换一个假的目标控制器。

@interface ExternStoryboardSegue : UIStoryboardSegue


@end


@implementation ExternStoryboardSegue


- (id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(ExternViewController *)destination
{
NSAssert(destination.storyboardName, @"storyboardName is required");


UIStoryboard *storyboard = [UIStoryboard storyboardWithName:destination.storyboardName bundle:nil];
UIViewController *vc = destination.sceneIdentifier
? [storyboard instantiateViewControllerWithIdentifier:destination.sceneIdentifier]
: [storyboard instantiateInitialViewController];


return [super initWithIdentifier:identifier source:source destination:vc];
}


- (void)perform
{
[[self.sourceViewController navigationController] pushViewController:self.destinationViewController animated:YES];
}


@end

ExternViewController 用作占位符,包含替换属性(StoryboardName 和 SceneIdentifier)所需的内容。

@interface ExternViewController : UIViewController


@property (strong, nonatomic) NSString *storyboardName;
@property (strong, nonatomic) NSString *sceneIdentifier;


@end


@implementation ExternViewController


@end

我们需要为占位符视图控制器设置这些属性和自定义类。

IB screenshot

从 Xcode 7(并移植回 iOS8)开始,您现在可以拥有故事板引用。这是在 WWDC 2015会议中提到的(它在第一个小时左右开始谈论它们)。基本上,您所要做的就是选择 ViewController,然后单击 编辑器-> 重构到故事板..。。给它起个名字,瞧瞧:

enter image description here

Please note that if you had VC's which are moved to the new storyboard, and are not referenced outside of it(what it should be), you should delete their references from main.storyboard(relax they will remain in newly created storyboard, you are deleting only references to them).

Xcode 8.2.1

您可以在外部情节串连板中引用视图控制器。

relationship from TabBarController to Storyboard Reference

drag a connection from the UITabBarController to the external Storyboard Reference, add it as a "view controllers" relationship. In the main storyboard it shows as "Item/square", but in the external storyboard you should add a UITabBarItem and define the name and image/s for the tab.

enter image description here

当选择 Storyboard Reference时属性检查器。

您还需要 在故事板中给外部控制器一个“ Storyboard ID” (此处未显示),并在引用中引用它的名称。

按照以下步骤完成这项任务:

步骤1 : 在组件中搜索 Storyboard Reference(参考屏幕快照)

步骤2 : 选择新的故事板引用

步骤3 : 提供新的故事板名称和初始视图控制器标识符的标识符(参考 Screen Shot)

enter image description here

构建和运行。它将工作。