如何在多个UIViewControllers之间共享一个Storyboard场景

15

我完全重新构思了这个问题,得知自己一开始走错了方向,但并没有解决问题。参考以下这张图片… storyboard illustration

我想要在代码中创建或操作转场(黄色高亮部分),使得Master视图是MFMasterViewController的多个子类(红色高亮部分)中任何一个。

当使用NIB文件时,我可以创建一个名为SharedNib.xib的NIB文件,并将其类设置为MFMasterViewController,然后创建我的子类,例如MFMasterViewControllerSubclassAMFMasterViewControllerSubclassB等等。然后使用以下代码实例化任何一个子类...

MFMasterViewControllerSubclassA *controller = [[MFMasterViewControllerSubclassA alloc] initWithNibName:@"SharedNib" bundle:nil];

或者...

MFMasterViewControllerSubclassB *controller = [[MFMasterViewControllerSubclassB alloc] initWithNibName:@"SharedNib" bundle:nil];

有什么线索可以告诉我如何在使用故事板时做到这一点?

在我的情况下,我之所以想要这样做,是因为我所有的子类都是相同的表视图和数据,但排序方式不同,并且在单元格的详细文本中写入一些不同的内容。我怀疑这是一个常见的模式。

谢谢和先行赞美, Pedro :)


我知道我可以通过为每个子类在我的Storyboard中复制场景来实现这一点,但当场景完全相同且所有版本都连接到相同的下一个场景时,这似乎是一种非常浪费的方式。 - Pedro
所以在故事板中的控制器分配给了类'MyViewController',而'MyViewControllerSubclass'是'MyViewController'的子类吗? - Justin Paulson
是的,对于这两个问题都是肯定的 :) - Pedro
我不明白为什么你要将 controller 分配给另一个名为 newViewControllerUIViewController?我会完全摆脱 UIViewController 并将第一行改为:MyViewControllerSubclass *controller = (MyViewControllerSubclass *)[[self storyboard] instantiateViewControllerWithIdentifier:@"SharedScene"]; 此外,请确保你的子类在 init 函数中调用 [super init] - Justin Paulson
这是一种速记方式。在实践中,当我使用 XIBs 时,它更像是 UIViewController *newViewController = [self methodThatInstantiatesSubclass];,具体取决于各种条件,该方法会分配 MyViewControllerSubclassA MyViewControllerSubclassB 等不同的子类。 - Pedro
显示剩余3条评论
4个回答

5
这不是一个直接的答案,但根据你的解释,这是我完成你想要的内容的方法。
基本上,你需要从 MFMasterViewController 中分离出 UITableViewDataSource (也许还有委托),这样在执行segue时,你就可以设置视图控制器中正确的dataSource和委托。
所以在导航控制器中,你需要实现 prepareForSegue:sender: 方法。这是你可以在执行segue之前自定义segue的地方:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // you can set the segue identifier using Interface Builder 
    // also it is a good thing to make sure which segue you're using
    if (([segue identifier] isEqualToString:@"TheId"]) {
       id<UITableViewDataSource> dataSource = [[TableViewDataSourceImplementationA alloc] init];
       [[[segue destinationViewController] tableView] setDataSource:dataSource];
    }
}

这样做可以让您获得所需的定制化,而无需创建您的视图控制器的子类。
如果您有WWDC视频的访问权限,请查看第407个会话“在应用程序中采用Storyboard”。

3

对于那些偶然发现这个问题的人,你也应该考虑更普遍地使用“策略”模式来替代子类化你的控制器。接受的答案是这种形式的,其中实现的策略来自于任何数据源/代理,并且可以在运行时切换。另一个例子是https://dev59.com/i3PYa4cB1Zd3GeqPoeWz#17381927


1
我相信我终于找到了答案。我们想要使用带有另一个类名的故事板ViewController。有许多解决方法,例如使用代理,但我认为这是最好的方法。我已经在另一个主题中回答过了。希望对您有所帮助!https://dev59.com/TmYq5IYBdhLWcg3w5Um8#32103618

1

如果您的.m文件未与任何故事板相关联,那么self.storyboard不就是空值吗?

  UIStoryboard *storyboard = [UIStoryboard storyboardWithName:
                                   @"MainStoryboard" bundle:[NSBundle mainBundle]];
    ViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"HauptMenu"];

请确保将storyboardWithName:更改为您的故事板的名称。

NSString * storyBoardName;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    storyBoardName = @"MainStoryboard_iPad";
} else {
    storyBoardName = @"MainStoryboard_iPhone";
}
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:
                                   storyBoardName bundle:[NSBundle mainBundle]];
ViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"HauptMenu"];

我例子中所调用的类MyViewController确实属于我的故事板场景,而且我问题中的前两个代码示例是有效的。MyViewControllerSubclass是MyViewController的一个子类,但是调用它的代码却失败了。 - Pedro
-(id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination{UIStoryboard *storyBoard= [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil]; UIViewController *viewController = [storyBoard instantiateViewControllerWithIdentifier:@"testIdentifier"]; // MyViewController* viewController= [[MyViewController alloc]initWithNibName:@"MyViewController" bundle:nil]; return [super initWithIdentifier:identifier source:source destination:viewController];} -(id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination{UIStoryboard *storyBoard= [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil]; UIViewController *viewController = [storyBoard instantiateViewControllerWithIdentifier:@"testIdentifier"]; // MyViewController* viewController= [[MyViewController alloc]initWithNibName:@"MyViewController" bundle:nil]; return [super initWithIdentifier:identifier source:source destination:viewController];} - prashant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接