How can I load storyboard programmatically from class? - ios

My problem is that I was looking for way to use both storyboard and xib. But I can't find proper way to load and show storyboard programmatically. Project was started developing with xib, and now it's very hard to nest all xib files in storyboard. So I was looking a way to do it in code, like with alloc, init, push for viewControllers. In my case I have only one controller in storyboard: UITableViewController, which has static cells with some content I want to show. If anyone knows proper way to work both with xib and storyboard without huge refactoring, I will appreciate for any help.

In your storyboard go to the Attributes inspector and set the view controller's Identifier. You can then present that view controller using the following code.
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [sb instantiateViewControllerWithIdentifier:#"myViewController"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];

Swift 3
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "viewController")
self.navigationController!.pushViewController(vc, animated: true)
Swift 2
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("viewController")
self.navigationController!.pushViewController(vc, animated: true)
Prerequisite
Assign a Storyboard ID to your view controller.
IB > Show the Identity inspector > Identity > Storyboard ID
Swift (legacy)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("viewController") as? UIViewController
self.navigationController!.pushViewController(vc!, animated: true)
Edit: Swift 2 suggested in a comment by Fred A.
if you want to use without any navigationController you have to use like following :
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = Storyboard.instantiateViewController(withIdentifier: "viewController")
present(vc , animated: true , completion: nil)

In attribute inspector give the identifier for that view controller and the below code works for me
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
DetailViewController *detailViewController = [storyboard instantiateViewControllerWithIdentifier:#"DetailViewController"];
[self.navigationController pushViewController:detailViewController animated:YES];

Try this
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"Login"];
[[UIApplication sharedApplication].keyWindow setRootViewController:vc];

in swift
NavigationController and pushController you can replace for
present(vc, animated:true , completion: nil)

For swift 4 and 5, you can do this. Good practice is set name of Storyboard equal to StoryboardID.
enum StoryBoardName{
case second = "SecondViewController"
}
extension UIStoryboard{
class func load(_ storyboard: StoryBoardName) -> UIViewController{
return UIStoryboard(name: storyboard.rawValue, bundle: nil).instantiateViewController(withIdentifier: storyboard.rawValue)
}
}
and then you can load your Storyboard in your ViewController like this:
class MyViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
guard let vc = UIStoryboard.load(.second) as? SecondViewController else {return}
self.present(vc, animated: true, completion: nil)
}
}
When you create a new Storyboard just set the same name on StoryboardID and add Storyboard name in your enum "StoryBoardName"

You can always jump right to the root controller:
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateInitialViewController];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];

The extension below will allow you to load a Storyboard and it's associated UIViewController. Example: If you have a UIViewController named ModalAlertViewController and a storyboard named "ModalAlert" e.g.
let vc: ModalAlertViewController = UIViewController.loadStoryboard("ModalAlert")
Will load both the Storyboard and UIViewController and vc will be of type ModalAlertViewController. Note Assumes that the storyboard's Storyboard ID has the same name as the storyboard and that the storyboard has been marked as Is Initial View Controller.
extension UIViewController {
/// Loads a `UIViewController` of type `T` with storyboard. Assumes that the storyboards Storyboard ID has the same name as the storyboard and that the storyboard has been marked as Is Initial View Controller.
/// - Parameter storyboardName: Name of the storyboard without .xib/nib suffix.
static func loadStoryboard<T: UIViewController>(_ storyboardName: String) -> T? {
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
if let vc = storyboard.instantiateViewController(withIdentifier: storyboardName) as? T {
vc.loadViewIfNeeded() // ensures vc.view is loaded before returning
return vc
}
return nil
}
}

Related

Access view controller from referencing storyboard

As I know that referencing storyboard can be used to make the multiple storyboard with the same storyboard reference. If all View Controllers hierarchy is connected via the segue it works.
I want to know how to use referencing storyboard without segue between View controllers, because one view controller may be used in multiple ways or may need to access the view controller with the storyboard identifier from the new referencing storyboard.
Please let me know, I want to use referencing storyboard's view controller without the segue.
You could do somthing like this...
#IBAction func tapButtonToShowOtherController(_ sender: Any?) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
//storyboard identifier set in storyboard "userSB"
let aVC = storyboard.instantiateViewController(withIdentifier: "userSB") as? AViewController
aVC?.udelegate = self
self.present(aVC!, animated: true, completion: nil)
}
Give the id to storyboard in identity inspecter like "ViewController_id"
MyCartViewController* destVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MyCartViewController_id"];
[self.navigationController pushViewController:destVC animated:YES];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
MyNewViewController *myVC = (MyNewViewController *)[storyboard instantiateViewControllerWithIdentifier:#"myViewCont"];
Select your viewcontroller from storyboard and select identity inspecter give stoary board id whatever you want
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"your storyboard name" bundle:nil];
MyNewViewController *myVC = (MyNewViewController *)[storyboard instantiateViewControllerWithIdentifier:#"your storyboard id"];
I downloaded sample at here https://www.raywenderlich.com/115697/ios-9-storyboards-tutorial-whats-new-in-storyboards
They have used storyboard reference as segue.Here i have modified something below:
1.select Checklists.stoaryboard
2.Remove ChecklistDetailViewController segue.
3.Select ChecklistsViewController.swift
4.Add following code:Its working without segue
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let storyboard = UIStoryboard(name: "ChecklistDetail", bundle: nil)
let aVC = storyboard.instantiateViewController(withIdentifier: "ChecklistDetailViewController") as? ChecklistDetailViewController
aVC?.checklist = checklists[indexPath.row]
navigationController?.pushViewController(aVC!, animated: true)
}
5.comment prepare(for segue: UIStoryboardSegue, sender: Any?) method.
Here i have understand:
When you are using, storyboard reference You need to mention ReferenceID
Then you can take viewcontroller by giving stoarboard name with Respective storyboardId

How to represent a startup screen in Storyboards

Right now I have a MainViewController which is embedded in a UINavigationController so the navigation controller is set as initial view controller.
What I want is first time the app starts and only then to show a StartupViewController. But I am not sure how to represent this in my storyboard.
Should this be set as initial view controller if the app starts the first time, if not the navigation controller should be set.
What I tried is to show StartupViewController in MainViewController::viewDidLoad(), but its not working how I wanted too.
Anyone know what is the right approach to do this ?
Hello this code may be helpfull for you :
// MARK: - Application Supporting Funcations -
func loadFirstViewController(viewController: String)
{
// for loading first view Controller
let storyBoard = appDelegate.AppStoryBoard()
/////////////////////////Add Navigation Controller and set Root View Controller///////////////////////////////////////
let object = storyBoard.instantiateViewControllerWithIdentifier(viewController) // for prelogin navigation
self.navigationController = UINavigationController(rootViewController: object)
self.navigationController?.navigationBar.hidden = true
self.loadNavigationControllerToWindow()
}
func loadNavigationControllerToWindow()
{
if self.window == nil
{
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
}
// for loading root view
self.window!.rootViewController = self.navigationController!
self.window!.makeKeyAndVisible()
}
call this function in didFinishLaunchingWithOptions
if((NSUserDefaults.standardUserDefaults().valueForKey("isFirstTime") != nil))
{
self.loadFirstViewController("LoginVC") // for loading first view controller
}
else
{
self.loadFirstViewController("WelcomeVC") // for loading first view controller
}
put this after you go in second controler viewDidLoad
if((NSUserDefaults.standardUserDefaults().valueForKey("isFirstTime") == nil))
{
NSUserDefaults.standardUserDefaults().setValue("1", forKey: "isFirstTime")
}
This is how I acheived in my app.
Add this in appdelegate applicationdidfinishlaunching.
NSUserDefaults *defaults =[NSUserDefaults standardUserDefaults];
if (![defaults boolForKey:#"FirstTime"])
{
//NSLog(#"Enter First Time ");
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
StartupViewController * firstViewController = [storyBoard instantiateViewControllerWithIdentifier:#"StartupViewController"];//AskAndAnswerViewId RegisterViewId TagViewId HelpViewId
self.navigationController=[[UINavigationController alloc]initWithRootViewController:firstViewController];
self.window.rootViewController = self.navigationController;
[self.navigationController setNavigationBarHidden:YES];
}
else
{
//NSLog(#"not First Time");
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]];
HelpViewController *mainviewcontroller = [storyBoard instantiateViewControllerWithIdentifier:#"AskAndAnswerViewId"];
self.navigationController=[[UINavigationController alloc]initWithRootViewController:mainviewcontroller];
self.window.rootViewController = self.navigationController;
[self.navigationController setNavigationBarHidden:YES];
}
Once you reached in Mainviewcontroller change the userdefault value for FirstTime to "NO".
I understand your Question ,
In AppDelegate try to set rootViewController ,
I have store data in the NSUserDefault if user came first time
And try to set rootViewController once he visit first time.
In below Example I have navigate user to Login screen/Home screen
let str = userDefaults.objectForKey("firstTime")
{}else{}
Please don't forget to give identifier to your view controller StartupViewController
-> user interaction enable in StartupViewController
if (UserDefaults.standard.string(forKey: "keepUsername") != nil) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "Revealview")
self.present(vc, animated: false, completion: nil)
}
else
{
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "loginview") as! loginview
self.present(nextViewController, animated:true, completion:nil)
}

Present View Controller in Storyboard with a Navigation Controller - Swift

I am currently showing a viewController in my new storyboard below:
var storyboard : UIStoryboard = UIStoryboard(name: AccountStoryboard, bundle: nil)
var vc : WelcomeViewController = storyboard.instantiateViewControllerWithIdentifier("WelcomeID") as WelcomeViewController
vc.teststring = "hello"
self.presentViewController(vc, animated: true, completion: nil)
However, this presents the viewcontroller without its embedded navigation controller.
I tried changing "WelcomeID" to the navigation controller within the storyboard - however to no success.
I got this working in Objective -C, however don't know how to transform into swift:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"SetupStoryboard" bundle:nil];
UINavigationController *navigationController1 = [storyboard instantiateInitialViewController];
navigationController1.modalPresentationStyle = UIModalPresentationFormSheet;
navigationController1.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
WelcomeViewController *vc = (WelcomeViewController *)navigationController1.viewControllers[0];
vc.teststring = #"Hello";
[self presentViewController:navigationController1 animated:YES completion:nil];
How can you do this in swift?
You're definitely on the right track. Unfortunately when you reference a view controller by its storyboard ID it will ignore the fact it is embedded within anything. Same goes for segues when you segue to something embedded, the destination view controller will be the embedding controller, not the controller you're usually interested in. Anyhow, you should be able to fix the problem in a similar way you've done in Objective-C, so this is just an exercise in syntax porting.
Edit: Define storyboard name with string now
let storyboard : UIStoryboard = UIStoryboard(name: "AccountStoryboard", bundle: nil)
let vc : WelcomeViewController = storyboard.instantiateViewControllerWithIdentifier("WelcomeID") as WelcomeViewController
vc.teststring = "hello"
let navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil)
OR you can give your embedding view controller an ID and instantiate that instead.
let secondViewController = self.storyboard?.instantiateViewControllerWithIdentifier("WelcomeID") as SecondViewController
self.navigationController?.pushViewController(secondViewController, animated: true)
Class Name is : SecondCiewController
The answer given by #Chris is works good in older version of swift.
Update Swift 3 & Swift 4
let storyboard : UIStoryboard = UIStoryboard(name: "AccountStoryboard", bundle: nil)
let vc : WelcomeViewController = storyboard.instantiateViewController(withIdentifier: "WelcomeID") as! WelcomeViewController
vc.teststring = "hello"
let navigationController = UINavigationController(rootViewController: vc)
self.present(navigationController, animated: true, completion: nil)
Thanks!!!
Remember to setup the modalPresentationStyle property, in programmatically present the IB settings are ignored.
let sb = UIStoryboard(name: "retail_carrello", bundle: nil)
guard let carrelloVC = sb.instantiateViewController(withIdentifier: "mainCarrello") as? retail_carrello else { return }
let navController = UINavigationController(rootViewController: carrelloVC)
navController.modalPresentationStyle = .fullScreen //<--- remember to set up this if you need fullscreen
present(navController, animated: true, completion: nil)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "SalesVC") as! SalesVC
navigationController?.pushViewController(vc, animated: true)

Programmatically change rootViewController of storyBoard

I have created my project using Storyboards. The root ViewController lies inside a Storyboard, I have not written a single code in the appDelegate.
Now I want to show a tour of my app, so I want to change the root ViewController from Tab Bar to my TourVC and when the tour of the app is finished , I want to again switch back my root ViewController to Tab Bar.
So I looked up online and followed the following points
1) Remove Storyboards from app.plist file,
2) Uncheck option "isInitialViewController" from Storyboards which is checked in case of Tab Bar controller because its a root ViewController,
3) Add this code in appDelegate.m file.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ProductTourViewController *PT = [[ProductTourViewController alloc] initWithNibName:#"ProductTourViewController" bundle:nil];
self.window.rootViewController = PT;
[self.window makeKeyAndVisible];
return YES;
But my app crashes with this error log,
[ProductTourViewController selectedViewController]: unrecognized selector sent to instance 0x1766a9e0
And also I get a warning,
Unsupported Configuration: Scene is unreachable due to lack of entry points and does not have an identifier for runtime access via -instantiateViewControllerWithIdentifier:.
Objective-C:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UITabBarController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"tabBarcontroller"];
[[UIApplication sharedApplication].keyWindow setRootViewController:rootViewController];
Swift :
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewControllerWithIdentifier("tabBarcontroller") as UITabBarController
UIApplication.sharedApplication().keyWindow?.rootViewController = viewController;
Swift 3:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarcontroller") as! UITabBarController
UIApplication.shared.keyWindow?.rootViewController = viewController
Swift 5:
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarcontroller") as! UITabBarController
UIApplication.shared.windows.first?.rootViewController = viewController
UIApplication.shared.windows.first?.makeKeyAndVisible()
Or simply like this:
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarcontroller") as! UITabBarController
self.view.window?.rootViewController = viewController
self.view.window?.makeKeyAndVisible()
Both works fine!
Set storyboard ID for your class in your main storyboard.
UIStoryboard *MainStoryboard = [UIStoryboard storyboardWithName:#"Main"
bundle: nil];
UINavigationController *controller = (UINavigationController*)[MainStoryboard
instantiateViewControllerWithIdentifier: #"RootNavigationController"];
LoginViewController *login=[MainStoryboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
[controller setViewControllers:[NSArray arrayWithObject:login] animated:YES];
self.window.rootViewController=controller;
In swift we can implement it is as following
let storyboard = UIStoryboard(name: "StartingPage", bundle: NSBundle.mainBundle())
let loginView: SignInVC = storyboard.instantiateViewControllerWithIdentifier("SignInVC") as! SignInVC
UIApplication.sharedApplication().keyWindow?.rootViewController = loginView
I use simple this:
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"NameOfStoryBoard" bundle:nil];
UITabBarController *rootViewController = [sb instantiateViewControllerWithIdentifier:#"NameOfTabBarController"];
[[UIApplication sharedApplication].keyWindow setRootViewController:rootViewController];
Just to add to Sunny Shah's answer, this is the Swift 3 version of it:
let mainStoryBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController: UIViewController = mainStoryBoard.instantiateViewController(withIdentifier: "MainTabBarController") as! UITabBarController
UIApplication.shared.keyWindow?.rootViewController = viewController
Swift 3 code:
Use below in didFinishLaunchingWithOptions Appdelegate function.
Replace "HomeViewController" with ViewController you want to set as Root ViewController on app launch.
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "HomeViewController")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
Swift 5 + Xcode 11:
Make like this:
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarcontroller") as! UITabBarController
UIApplication.shared.windows.first?.rootViewController = viewController
UIApplication.shared.windows.first?.makeKeyAndVisible()
Or like this:
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarcontroller") as! UITabBarController
self.view.window?.rootViewController = viewController
self.view.window?.makeKeyAndVisible()
Both works fine!
Objective c
step 1: remove main story board from info.plist
step 2: add storyboard id to your view controller in your interface builder
step 3: add the following code to application did finish method in app delegate
self.window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
//set main story board
if( condition){
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"StoryboardName1" bundle:nil];
UIViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"ViewController1"];
[[UIApplication sharedApplication].keyWindow setRootViewController:rootViewController];
[self window].rootViewController = rootViewController;
[self.window makeKeyAndVisible];
}else{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"StoryboardName2" bundle:nil];
UIViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[[UIApplication sharedApplication].keyWindow setRootViewController:rootViewController];
[self window].rootViewController = rootViewController;
[self.window makeKeyAndVisible];
}
This is an old article, but I will reply.
I do not recommend the following code.
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "tabBarcontroller") as! UITabBarController
UIApplication.shared.keyWindow?.rootViewController = viewController
Because you are creating two instances.
I recommend writing the following code in the appropriate ViewController.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = self

Present storyboard ViewController from another ViewController

I have multiple UIViewControllers in my iOS App's Storyboard. I want to open one of the UIViewControllers (in the storyboard) from a different UIViewController.
I've tried the code below, but it isn't working even though I used it before iOS 5 and it worked fine.
- (IBAction)addNotes:(id)sender {
NotesViewController *notesView = [[NotesViewController alloc] initWithNibName:#"NotesViewController" bundle:nil];
[self presentModalViewController:notesView animated:YES];
}
How can I perform this action with iOS 5 Storyboards?
Assuming you have storyboard, go to storyboard and give your VC an identifier (inspector), then do:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"IDENTIFIER"];
[self.navigationController pushViewController:vc animated:YES];
Assuming you have a xib file you want to do:
UIViewController *vc = [[UIViewController alloc] initWithNibName:#"NIBNAME" bundle:nil];
[self.navigationController pushViewController:vc animated:YES];
Without a xib file:
UIViewController *vc = [[UIViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
Following will work on Swift 3.0 and above.
StoryBoard
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let mainViewController = storyBoard.instantiateViewController(withIdentifier: "Identifier")
self.navigationController?.pushViewController(mainViewController, animated: true)
.xib
let viewController = UIViewController(nibName: "NibName", bundle: nil)
self.navigationController?.pushViewController(viewController, animated: true)
Without .xib
let viewController = UIViewController()
self.navigationController?.pushViewController(viewController, animated: true)
Swift 5
let storyboard = UIStoryboard(name: "YourStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ControllerIdentifier")
self.present(vc, animated: true, completion: nil)
Update with the Swift 3.1 version
if you haven't embed navigation controller then
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController2 = storyBoard.instantiateViewController(withIdentifier: "ViewController2")
self.present(viewController2, animated: true, completion: nil)
and, if you had embed navigation controller then
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController2 = storyBoard.instantiateViewController(withIdentifier: "ViewController2")
self.navigationController?.pushViewController(viewController2, animated: true)
In swift 4.2 answer for those who want this answer without navigation in modally and in swift updated versions.
let storyboard = UIStoryboard(name: "YourStoryboardName", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "mainViewController")
self.present(controller, animated: true, completion: nil)
UIViewController *initialHelpView = [[UIStoryboard storyboardWithName:#"StoryBoard_IDentifier" bundle:nil] instantiateViewControllerWithIdentifier:#"ViewController_Identifier"];
[self presentViewController:initialHelpView animated:YES completion:nil];

Resources