15

I'm completely re-formulating this question having learned that I was originally off track but that having me no closer to solving the problem. With reference to this image... storyboard illustration

I am wanting to either create or manipulate the segue (highlighted in yellow) in code such that the Master view is any one of a number of subclasses of MFMasterViewController (highlighted in red).

When doing this using Nibs I could create a Nib, SharedNib.xib & set the class as MFMasterViewController, then create my subclasses, say MFMasterViewControllerSubclassA, MFMasterViewControllerSubclassB etc. & then instantiate whichever subclass I wanted using...

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

or...

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

etc.

Any clues as to how I can get this right using storyboards?

In my case the reason for wanting to do this is that all my subclasses are the same tableview & data but sorted differently & having some difference in what's written to the detail text of the cels. I suspect that it is a not uncommon pattern.

Cheers & TIA, Pedro :)

Pedro
  • 866
  • 1
  • 12
  • 28
  • I am aware that I could do this by making in my storyboard a copy of the scene for every subclass but that seems a pretty wasteful way to go when the scene is exactly the same & all versions segue to the same next scene. – Pedro Sep 04 '12 at 18:02
  • So is the controller in the storyboard assigned to class 'MyViewController` and is `MyViewControllerSubclass` a subclass of `MyViewController` – Justin Paulson Sep 04 '12 at 19:11
  • Yes to both questions :) – Pedro Sep 05 '12 at 01:04
  • I don't understand why you are trying to assign `controller` to another `UIViewController` called `newViewController`? I would get rid of the `UIViewController` all together and change the first line to this: `MyViewControllerSubclass *controller = (MyViewControllerSubclass *)[[self storyboard] instantiateViewControllerWithIdentifier:@"SharedScene"];` Also, make sure your subclass calls `[super init]` in the `init` function. – Justin Paulson Sep 05 '12 at 19:49
  • That's a shorthand. In practice, & what I did have when using XIBs, it'd be more like `UIViewController *newViewController = [self methodThatInstantiatesSubclass];` where, depending on various conditions, `MyViewControllerSubclassA` or `MyViewControllerSubclassB` etc. is assigned by the method. – Pedro Sep 06 '12 at 01:37
  • That's your problem. You are creating a sublcass of `UIViewController` then trying to assign it to a `UIViewController`. it doesn't work that way. Why are you trying to make them into `UIViewController`? You need to make `newViewController` match the subclass that it actually is. – Justin Paulson Sep 06 '12 at 13:05
  • Perhaps my reformulation of the question will make it all clearer. – Pedro Sep 07 '12 at 14:20
  • Okay, that navigation controller is going to automatically instantiate MFMasterViewController as the rootViewController of the navigationController, where and how is it supposed to determine when you are switching from subclassA to subclassB? – Justin Paulson Sep 07 '12 at 14:50

4 Answers4

5

It's not a direct answer but this is how I would accomplish what you want based on your explanation of the reason.

Basically you need to separate the UITableViewDataSource (and maybe the delegate too) from the MFMasterViewController so when the segue is executed you can set the correct dataSource and delegate in the view controller.

So in the Navigation Controller you need to implement the prepareForSegue:sender: method. This is where you can customize the segue before it is executed:

- (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];
    }
}

This way you can get the customization you want without the need to create subclasses of your view controller.

And if you have access to WWDC videos, check the session #407 Adopting Storyboards in Your App.

Felipe Cypriano
  • 2,697
  • 20
  • 32
3

For anyone stumbling upon this question, you should also consider more generally using a "Strategy" pattern as an alternative to subclassing your controller. The accepted answer is a form of that, where the strategy implemented comes from whatever the data source/delegate is, and can be switched out at runtime. Another example of this is https://stackoverflow.com/a/17381927/954643

Community
  • 1
  • 1
qix
  • 6,008
  • 1
  • 44
  • 58
1

If your .m file is not associated with any storyboard, wouldn't self.storyboard be Nil?

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

Make sure to change the storyboardWithName: to whatever your storyboard is named.

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"];
prashant
  • 1,884
  • 13
  • 26
  • The class I've called MyViewController in my example does belong to the scene in my storyboard & the first 2 code examples in my question work. MyViewControllerSubclass is a subclass of MyViewController but the code invoking that is what fails. – Pedro Sep 04 '12 at 18:11
  • - (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 Sep 04 '12 at 18:22
1

I believe i finally found the answer. We want to use storyboard ViewController with another class name. There are many workarounds like using delegates but i think this is the best one. I already answered it in another topic. Hope it helps! https://stackoverflow.com/a/32103618/1943053

Community
  • 1
  • 1
Jiří Zahálka
  • 7,009
  • 2
  • 19
  • 17