Looking to maximize reuse in an iPhone storyboard application - iphone

I'm programming a complex storyboard application and I'm encountering some issues when it comes to code re-use across view controllers and different application paths.
Can I segue to a ViewController that is not directly connected to the current one?
How do I segue out from a button to several ViewControllers conditionally? Connecting both does not work.
Can I enter the ViewController sequence from an arbitrary position in the application?
Just a few questions that come up. Anybody have any ideas or good examples?

Can I segue to a ViewController that is not directly connected to the current one?
Not with a segue. But you can push or present a viewController from a storyboard modally, like you did with .xib files.
// if self was created from code or from a .xib:
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"MainStoryBoard" bundle:nil];
// if self was instantiated from within a storyboard:
UIStoryboard *storyBoard = self.storyboard;
MyFancyViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"MyFancyViewControllerIdentifier"];
[self presentModalViewController:viewController animated:YES];
But you have to set the identifier first. Select the viewController in the storyboard and do that in the attributes inspector.
Once the MyFancyViewController is visible you can use all its segues. It might feel strange to switch between code and storyboard segues, but there is nothing wrong with that. It makes the whole storyboard thing really usable.
How do I segue out from a button to several ViewControllers conditionally? Connecting both does not work.
Add two or more segues that start from the viewController (not from a button or any other view. E.g. start your control-drag at the statusbar) to the target viewControllers. Set identifiers for them and use some code like this:
if (someState) {
[self performSegueWithIdentifier:#"MyFirstSegueIdentifier" sender:somethingOrNil];
}
else {
[self performSegueWithIdentifier:#"MySecondSegueIdentifier" sender:somethingOrNil];
}
Can I enter the ViewController sequence from an arbitrary position in the application?
Yes, if you use "old school" view controller management. Similar to the first part. Instantiate your viewController and present it with code.

Related

Getting Initial View Controller from Storyboard inside the App Delegate

I am trying to access the initial viewcontroller of my storyboard. It is a navigation controller which is wired up to a second viewcontroller via a seque. So after my application did finish launching I want to directly show the viewController that is connected through the segue. I tried it out with code like this but it doesn't work ...
UINavigationController *navController = (UINavigationController*)self.window.rootViewController;
[navController.topViewController performSegueWithIdentifier:#"showLoginScreen" sender:self];
What am I doing wrong?
4 years later:
If I look at my question again after 4 years, I honestly have no idea what my real problem was.
Be sure you have tick marked the
is initial ViewController
option for UINavigationController in storyBoard
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UINavigationController * myStoryBoardInitialViewController = [storyboard instantiateInitialViewController];
Sebastian, I'm not sure why you would want to start the initial view controller manually - all my projects (which all use storyboards) do this automatically if you ticked "Use Storyboards" on the second screen in the "New Project" wizard.
Maybe you need to mark the storyboard scene as inital? This can be done in the scene's attribute inspector by ticking the "Is Initial View Controller" - rather obviously named.
And then - if you really have a unusual setup which requires you to access the scenes manually, you can use the following:
UIStoryboard *sb = [UIStoryboard storyboardWithName: "StoryboardName"
bundle: [NSBundle mainBundle]];
UIViewController *vc = [sb instantiateInitialViewController];
(Beware - no code completion here, so check spelling again.)
Or maybe I am getting your question completely wrong..? Happy hacking!
In my app i have tabBar
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
TabBarController *tabBar = [storyBoard instantiateViewControllerWithIdentifier:#"TabBarController"];
_window.rootViewController = tabBar;
Ok, here is a reason in the year 2022 pre SwiftUI apps. Your apps starts... it has several choices, one, it wants you to login, two it wants you to sync with home base, and three everything is fine and just show the main UI. Case two may refresh a rather large body of information before you build out you main UI.

iPhone storyboard present a model view Programmatically

Am Developing a iphone appliction using this storyboard concept.
Here I have done the initial-view present using this storyboard.
Here I have created a button in rootviewcontroller programatically on user clicking on this button i should present another view controller lets say root2ViewController. Am using below code the present the view but its not presenting anything and it says like identifier not found. Any solution and idea will be appreciated.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle:[NSBundle mainBundle]];
UIViewController *root2ViewController = [storyboard instantiateViewControllerWithIdentifier:#"MyIdentifier"];
[root2ViewController setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentViewController:root2ViewController animated:animation completion:nil];
In the inspector window in you storyboard you need to set the storyboard identifier of you view controller
I Found the solution calling this below method in action is did the magic.
[self performSegueWithIdentifier: #"FindMyClinic" sender: self];

UIView presented with Black screen, fix?

I call a View to be presented with the following code:
#import "infoView.h"
...
infoView *viewInfo = [[infoView alloc] initWithNibName:nil bundle:nil];
viewInfo.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewInfo animated:YES];
But when it is presented in run-time the view that is loaded turns out black.
Currently I am using storyboard, but I need to use this code, for it is a lot more efficient in my case, because I am dealing with multiple views!
It works fine if I connect it via StoryBoard.
I should be seeing 2 labels, 1 UITextView, and 2 UIButton.
The view was created using StoryBoard, when the .m and .h files for the view where created I did not add a .xib for it. And also it is linked through the "Custom Class" section in StoryBoard.
Thanks, hope someone can help!
It's generally pretty bad form to mock people who are taking the time and effort to help you.
Naming is important it makes your code easier to work with and allows other people to use it. Not following the conventions for the language you are working in is dangerous and means that your code is not compatible with other developers as things are interpreted differently.
If you look at the docuemntation for UIViewController you'll see this note in the initWithNibName:bundle: method description
If your app uses a storyboard to define a view controller and its associated views, your app never initializes objects of that class directly. Instead, view controllers are either instantiated by the storyboard—either automatically by iOS when a segue is triggered or programmatically when your app calls the storyboard object’s instantiateViewControllerWithIdentifier: method. When instantiating a view controller from a storyboard, iOS initializes the new view controller by calling its initWithCoder: method instead. iOS automatically sets the nibName property to a nib file stored inside the storyboard.
Therefore you are instantiating your controller wrong, the storyboard should be instantiating it. Which is done like this (naming corrected)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle bundleForClass:[self class]]];
InfoViewController *infoViewController = [storyboard instantiateViewControllerWithIdentifier:#"InfoViewController"];
infoViewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self infoViewController animated:YES];
Side note
infoView is a bad name for the class not only because you didn't start with a capital but also because it's completely deceiving. Anyone reading this would assume that InfoView is a subclass of UIView not UIViewController.

iOS - Interface Builder Outlets Not Initialized

I have created a view in Interface Builder with some labels and text as IBOutlets. I can view this screen perfectly when I segue to it from another view that I have defined in my Storyboard.
However, I have another XIB and an associated UIViewController that I want to access that view from. Because my XIB is not in the Storyboard, I cant segue to it. Instead I have to execute the transition programmatically.
PlantDetailViewController *plantDetailVC = [[PlantDetailViewController alloc] init];
[self.currentNavigationController pushViewController:plantDetailVC animated:YES];
When this code is executed it transitions to the view but the view is just blank. I have debugged the code and it enters viewDidLoad and viewWillAppear however all my IBOutlets are NIL....so nothing it showing up on screen!
Can anyone tell me why they might be NIL and how I can initialize them?
Thanks
Brian
It sounds like you're saying you have a PlantDetailViewController set up in your storyboard, and some OtherViewController that was created outside of your storyboard. Now you want OtherViewController to instantiate the PlantDetailViewController that was set up in your storyboard.
Let's say your storyboard is named MainStoryboard.storyboard.
First, you need to set the identifier of the PlantDetailViewController in your storyboard. You do this in the Attributes inspector, under the View Controller section. Let's say you set it to PlantDetail.
Then, in OtherViewController, this should work:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
PlantDetailViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"PlantDetail"];
[self.currentNavigationController pushViewController:vc animated:YES];
-init doesn't load a nib file for you, if you want to load a nib use -initWithNibName:bundle:
If you use nib naming conventions you can pass nil to load a nib whose name matches your class and the default bundle, i.e. [[PlantDetailViewController alloc] initWithNibName:nil bundle:nil], see the docs for -nibName for details.

Navigation & View Controller questions

I'm experimenting with ViewControllers & NavigationControllers in Interface Builder trying to get a better grasp of what's tied to what and why... I'm struggling with a scenario that has confused me. Hopefully someone can set me straight...
Say I start with your typical iPhone template View-Based Application and I display a view which is handled by view controller (viewController). Then after a certain event I'd like to replace that view with a "typical" Navigation-Based View (rootVC). I'd like to create as much as possible in IB. My questions have to do with how to show rootVC and remove all traces of the previous viewController as user will never need to return and where/how to wire in the navController in IB. Currently when it's time to show the rootVC I do the following in my viewController:
RootVC *rvc = [[RootVC alloc] initWithNibName:#"RootVC" bundle:nil];
[rvc.view setFrame:[[UIScreen mainScreen] applicationFrame]];
ViewTestAppDelegate *appDelegate = (ViewTestAppDelegate *)[[UIApplication sharedApplication] delegate];
self.rootVC = rvc;
[rvc release];
[appDelegate.viewController.view removeFromSuperview];
[appDelegate.window addSubview:rootVC.view];
[appDelegate.viewController release];
rootVC displays except viewController still has a retain count of 1?!?
Also, where should rootVC's navigationController be instantiated? Having started with the View-Based template the MainWindow.xib contains an object for the viewController (which has its own ViewController.xib) an appDelegate and a UIWindow. My RootVC.xib contains a UITableView. Do I need yet another intermediary view controller that will have another ApplicationDelegate object that I wire up to a UIWindow object and a UINavigationController? The View Controller that comes along with IB's Navigation Controller object would then be set to my RootVC class?
Sorry for the verbosity. It's difficult for me to explain. Because some objects in IB are proxies and some are "real" it's sometimes confusing (to me) when trying "new" things out what's required, where & when. Basically I want to know to go about setting up one view leading to another with no way back to first view. 2nd view basically becomes the "main" root spawning off in many directions...
I would recommend using the navigation-based iPhone application template and presenting your one-time view as a modal view on top of the root view.
I was able to figure it out by putting a reference to the viewController in the MainWindow nib and then autoreleasing the viewController after I added the navigationController & rootVC to the UIWindow. Learned another thing or two about IB along the way. Pretty powerful...