reuse storyboard and uicontrollers - ios

I have designed in a storyboard a login/password Controller. The textfields are linked to the controller with the famous ctrl+drag.
Is there a way to reuse storyboard + controller somewhere else in the App. For instance I want to give the user the ability to change his login from a setting menu and I do not want to have to create a new class and to clone its storyboard representation.
What is the best practice in this case to reuse what I have already done?

This is what view controller's identifiers are used for.
In your storyboard, set an identifier for LoginViewController, after that, you'll only need to present your LoginViewController or push it to your navigation stack. Your code should look something like this:
let storyboard = UIStoryboard(name: "yourStoryboardName", bundle: nil)
let loginViewController = storyboard.instantiateViewController(withIdentifier: "loginViewController") as! LoginViewController
// If you are in a navigation controller:
self.navigationController?.pushViewController(loginViewController, animated: true)
// If you just want to present a new view:
self.present(loginViewController, animated: true, completion: nil)
This way, you'll push/present a new view controller that has the layout specified in storyboard for the identifier "loginViewController".
All text fields and buttons in that view controller should be handled in the class specified for the view controller which, in your case, should be LoginViewController.

Ofcourse you can. I'm using this code.
Try:
OBJECTIVE-C:
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:storyBoardName bundle:nil];
UIViewController *upcomingViewController = [storyBoard instantiateViewControllerWithIdentifier: storyBoardID];
UINavigationController *controller = [[UINavigationController alloc] initWithRootViewController:upcomingViewController];

Related

How To addSubViews To Storyboard, Then Displaying It Using A Segue

I have a view controller reference to a storyboard of a given identifier. I'm adding a bunch of buttons to it, then trying to display it via a segue.
My problem is that when the segue fires, it creates a difference instance of the view controller with the same segue identifier, and thus it's blank.
What's the best practice to addSubView() to a storyboard, then getting that SAME storyboard object to display?
CLARIFICATION
Here's the flow I'm using:
Central VC -> Create SubVC using centralized Storyboard Object -> Adding SubViews to that SubVC in a factory class -> Queue Segue from SubVC back to the Central VC for segue using its identifier -> [it creates a NEW VC without my additions]
If you're using segues, then the Storyboard creates the destination viewController. If you want to customize the destination viewController, then you do that in prepareForSegue.
You can instantiate a view by code, and pushing in to you navigation controller, it's a clean approach and dont mess the Storyboard with unnecessary segues.
Just instantiate the next view (you must first give this view an StoryBoard ID), call it by code, and push it in the navigation controller.
Objective-C
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"storyBoard_Name" bundle:nil];
UIViewController* controller = [storyboard instantiateViewControllerWithIdentifier:#"ViewController_ID"];
[self.navigationController pushViewController:viewControllerName animated:YES];
Swift
let storyboard = UIStoryboard(name: "storyBoard_Name", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("ViewController_ID") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)

Sidebars on different ViewControllers using same SWRevealViewController

I have used SWRevealViewController to create side bar. As in this I have used my HomeViewController as front and SidebarViewController as right.
My SidebarViewController contain a UITableView(Having different subject names). I want to open a new ViewController say QuestionsViewController on selection of any subject.
Now my problem is I want to use SWRevealViewController again to have a sidebar in QuestionViewController but in SWRevealViewController identifier for front segue sw_front is a constant string so how can I change it or having any other way to have that sidebar in QuestionViewController also.
In Short : Can we have same sidebars in different ViewControllers using SWRevelViewController
Try this one:
create NavigationViewController with HomeViewController,
segue the RevealViewController to the NavigationController as "reveal view controller set controller",
segue HomeViewController to the QuestionViewController as "show",
on both add "bar button item"(named:"OpenSideBar") on the left of the NavBar,
create an outlet to both in their swift files and add to your viewDidLoad next:
OpenSideBar.target = self.revealViewController()
OpenSideBar.action = Selector("revealToggle:")
**worked for me
Simply connect your RevealViewController to your new view controller with "reveal view controller set controller" segue
I got a solution for this, we can change front and rear ViewControllers by using following code.
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
[self.revealViewController setRightViewController:[storyBoard instantiateViewControllerWithIdentifier:#"SideBarVC"]]; // To change rightViewController
[self.revealViewController setFrontViewController:[storyBoard instantiateViewControllerWithIdentifier:#"HomeVC"] animated:YES]; // To change frontViewController
For this we have to use SWRevealViewControllerSeguePushController as segue class for other FrontViewControllers
Thanks everyone for your help.

Navigation Controller from a View Controller

I'm using .xib files in an app. And I want to have two view controllers normal way and from the third view controller, embed it in a navigation view controller. Here's an illustration of how I want it.
I know I can embed a navigation controller in a modally presented view controller like this.
let firstVC = FirstViewController(nibName: firstViewController, bundle: nil)
let navController = UINavigationController(rootViewController: firstVC)
presentViewController(navController, animated: true, completion: nil)
But if I embed it in a navigation controller and push it, the app crashes with the error Pushing the same view controller instance more than once is not supported.
let firstVC = FirstViewController(nibName: firstViewController, bundle: nil)
let navController = UINavigationController(rootViewController: firstVC)
navController.pushViewController(firstVC, animated: true)
Is it possible to do this at all? If so, can someone please explain how?
Thank you.
NOTE: Don't confuse the code snippets with the diagram above. The firstViewController in the code is not the first view controller in the diagram.
Suppose that FirstViewcontroller,Secondviewcontroller,Thirdviewcontroller are the three view controllers. then the transition from second to third view controller use the code given below.
Secondviewcontroller *second=[[Secondviewcontroller alloc]init];
UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController: second];
[self presentViewController:nav animated:NO completion:nil];
use the first view controller as the root view controller of the UINavigationController
use the following method to present your next view controller
[self.navigationController pushViewController:vc animated: YES];
in the viewWillAppear method, if you wanna hide the navigation bar, use
[self.navigationController setNavigationBarHidden:YES animated:animated];
If you wanna show the navigation bar, use
[self.navigationController setNavigationBarHidden:NO animated:animated];

load view form StoryBoard that does not have a Segue

I am really liking having all of my view's laid out in the Storyboard but there are times when I will have a view that is shown based on a button that is generated by code so there will be no Segue reference - it will be totally disconnected in the Storyboard. I would still like to design it in the storyboard though so I can have a nice overview of all my screens.
Is it possible for me to load the XIB (or whatever it is in a storyboard) designed in the storyboard when a UIViewControler is loaded?
I do this in my projects:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *myController = [storyboard instantiateViewControllerWithIdentifier:#"MyViewController"];
[self.navigationController pushViewController: myController animated:YES];
Just make sure you have set your controller's identifier correctly. You can do this by:
selecting the controller in Storyboard
in the Utilities panel, click the Attributes inspector. Whatever you decide to put in the Identifier field is what goes in the 'instantiateViewControllerWithIdentifier' statement.
I hope this helps.
You must assign a Storyboard ID to your view controller.
IB > Show the Identity inspector > Identity > Storyboard ID
Swift
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewcontroller = storyboard.instantiateViewControllerWithIdentifier("viewController")
as? UIViewController
if let navigationController = self.navigationController {
navigationController.pushViewController(viewcontroller!, animated: true)
}

UIStoryboard: What's the Correct Way to Get the Active Storyboard?

I am currently furiously digging through all the docs, and haven't quite found what I'm looking for. I suspect it is a real d'oh! answer.
I simply need to find the active storyboard in the main bundle, and want to know the best way to do this.
This is so that I can use the [UIStoryboard storyboardWithName:#"XXX" bundle:mainBundle] to extract the running storyboard.
I know how to kludge it by switching on the idiom, but I feel that this is a...kludge.
What's a correct way of doing this?
In case you want to get the active storyboard for a viewController, there's a storyboard property. This is how I solved it, instead of making a new instance:
LoginViewController *vc = [navController.storyboard instantiateViewControllerWithIdentifier:#"firstLaunch"];
[navController presentModalViewController:vc animated:YES];
In Swift you'd call:
let loginViewController = navigationController?.storyboard?.instantiateViewController(withIdentifier: "firstLaunch") as! LoginViewController
navigationController?.present(loginViewController, animated: true, completion: nil)
You could also be a lot safer by using guards against the navigation controller and the storyboard. I've used as! so as to guarantee that you're getting a LoginController.
OK. As my comment above indicates, I found the answer to the (badly phrased question):
I wanted to be able to get the main (not active) storyboard, as I'm not using multiple storyboards per incarnation. I'm using the standard model of 1 storyboard for iPhone, and 1 for iPad. I just wanted the cleanest way to get the storyboard, so that I could use it to generate a view controller.
I found the answer in this post on Stack Overflow, and implemented it with the following code:
UIStoryboard *st = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary objectForKey:#"UIMainStoryboardFile"] bundle:[NSBundle mainBundle]];
In Swift, you'd use the following syntax:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
Note that passing nil to bundle will make the call refer to your main bundle automatically.
If you're in a view controller that you have on the Storyboard and want to instantiate the Storyboard from there directly, you can just do:
let storyboard: UIStoryboard? = self.storyboard // call this inside a VC that is on the Storyboard
Note that in the last case, self.storyboard will return an optional Storyboard (Storyboard?), so if you'd like to use it unwrap it like so:
if let storyboard = self.storyboard {
// access storyboard here
}
The better approach would be to get existing storyboard instance from window's rootViewController if not available then create a new instance.
let storyboard = self.window?.rootViewController?.storyboard ?? UIStoryboard.init(name: "Main", bundle: nil)
Also using globally accessible helper functions like these can be a good idea provided that you pass the already active storyboard as parameter.
class Helper {
static func getLoginVC(storyboard: UIStoryboard) -> LoginVC {
return storyboard.instantiateViewController(withIdentifier: String(describing: LoginVC.self)) as! LoginVC
}
}
you can pass the active storyboard instance from a controller like this -
let loginVC = Helper.getLoginVC(storyboard: self.storyboard)
In case you are trying to access storyboard from appDelegate or sceneDelegate you can use -
let storyboard = self.window?.rootViewController?.storyboard ?? UIStoryboard.init(name: "Main", bundle: nil)
let loginVC = Helper.getLoginVC(storyboard: storyboard)
let navigationController = UINavigationController.init(rootViewController: loginVC)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
I have just copy pasted the code form above updated question so that everyone can see it as an answer.
UIStoryboard *st = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary objectForKey:#"UIMainStoryboardFile"] bundle:[NSBundle mainBundle]];

Resources