Unable to Instantiate View Controller - ios

I have a function, whereby I check if the UserDefaults are set and if not a new View Controller opens and presents a login screen which will set the user defaults.
My problem is the view controller does not Instantiate but I get a print "User not registered"
func checkUserAccount() {
let defaults = UserDefaults.standard
let accountName = defaults.bool(forKey: "PUserAccountName")
let accountPassword = defaults.bool(forKey: "PUserAccountPassword")
if accountName == true && accountPassword == true {
print("User Registered")
} else {
let storyboard: UIStoryboard = UIStoryboard(name: "PolTRiM", bundle: nil)
let vc: StudentLoginVC = storyboard.instantiateViewController(withIdentifier: "studentLogin") as! StudentLoginVC
vc.modalPresentationStyle = .custom
vc.modalTransitionStyle = .crossDissolve
self.present(vc, animated: true, completion: { _ in })
print("User not registered")
}
}
Any thoughts?

Have you double checked UIStoryBoard name and UIViewController identifier if it's written correctly? Otherwise this code is working for me
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier :"MyViewController") as! UIViewController
self.present(viewController, animated: true)

Related

Moving to another storyboard inside closure

api.postUserLogin(Parameters: params) { (json) in
print(json)
if (json["status"].string == "true") {
self.user.id = json["data"]["id"].string
self.user.verify_status = json["data"]["verify_status"].string
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "MainViewController") as UIViewController
present(vc, animated: true, completion: nil)
}
}
Try this code:
func callViewController(){
let viewController: UIViewController = UIStoryboard(name:"STORYBOARD_NAME",bundle:nil).instantiateViewController(withIdentifier: "MainViewController")
let window :UIWindow = UIApplication.shared.keyWindow!
window.rootViewController = viewController
window.makeKeyAndVisible()
}

Dismiss Login Screen in iOS when using Parse

override init() {
super.init()
parseLoginHelper = ParseLoginHelper {[unowned self] user, error in
// Initialize the ParseLoginHelper with a callback
if let error = error {
// 1
ErrorHandling.defaultErrorHandler(error)
} else if let _ = user {
// if login was successful, display the TabBarController
// 2
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewControllerWithIdentifier("TabBarController")
// 3
self.window?.rootViewController!.presentViewController(tabBarController, animated:true, completion:nil)
}
}
}
So I understand that the code here should be able to replace my login screen upon hitting login, however, it does not. Instead it loads and stays on the login screen for parse. However, if I exit the app, it loads the proper screen. Does anyone have any ideas how to dismiss login screen more efficiently upon login?
let user = PFUser.currentUser()
let startViewController: UIViewController;
if (user != nil) {
// 3
// if we have a user, set the TabBarController to be the initial view controller
let storyboard = UIStoryboard(name: "Main", bundle: nil)
startViewController = storyboard.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
} else {
// 4
// Otherwise set the LoginViewController to be the first
let loginViewController = PFLogInViewController()
loginViewController.fields = [.UsernameAndPassword, .LogInButton, .SignUpButton, .PasswordForgotten]
loginViewController.delegate = parseLoginHelper
//loginViewController.signUpController?.delegate = parseLoginHCelper
startViewController = loginViewController
}
// 5
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = startViewController;
self.window?.makeKeyAndVisible()
return false
}
I believe you should not call
self.window?.rootViewController!.presentViewController(tabBarController, animated:true, completion:nil)
instead if you already in some controller why just go to tabBar like that:
presentViewController(tabBarController, animated:true, completion:nil)
You should not use :
self.window?.rootViewController!.presentViewController(tabBarController, animated:true, completion:nil)
Try to change that line by :
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("tabBarController") as! tabBarController
self.presentViewController(vc, animated: true, completion: nil)
and in your storyboard, set the storyboard id of tabBarController under identity inspector to : tabBarController

The right way to set a viewController as a root viewController

In the scenario where you have a viewController which you want to present as root view above everything else what is the right way to do this?
let Storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let MY_VIEW = Storyboard.instantiateViewControllerWithIdentifier("VIEWID")
//Is this the right way?
UIApplication.sharedApplication().delegate.window?.rootViewController?.presentViewController(MY_VIEW, animated: true, completion: nil)
//Or this?
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(MY_VIEW, animated: true, completion: nil)
In other words why would you use UIApplication.sharedApplication().delegate.window? over UIApplication.sharedApplication().keyWindow?.rootViewController? and in what scenarios? What would be the pros/cons of using one or the other?
You can do as follow.
let rootController = storyboard.instantiateViewControllerWithIdentifier("VIEWID") as! SplashVC
if self.window != nil {
self.window!.rootViewController = rootController
}
advantage of this is not getting crash when window is nil.
Another way is that(Most secure way i think)
let navigationController:UINavigationController = storyboard.instantiateInitialViewController() as! UINavigationController
let rootViewController:UIViewController = storyboard.instantiateViewControllerWithIdentifier("VIEWID") as! LoginVC
navigationController.viewControllers = [rootViewController]
self.window?.rootViewController = navigationController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController: MainViewController = storyboard.instantiateViewControllerWithIdentifier("MainViewController") as! MainViewController
let rootViewController = self.window!.rootViewController as! UINavigationController
rootViewController.pushViewController(viewController, animated: true)

3D touch to UITabView

I am using a tabViewController and want to know how I can make a 3D touch action from the home screen bring up a tab. I already have the code but can't seem to get a specific tab to show up; I can only get a window. My AppDelagate.swift is below. Any help?
enum ShortcutIdentifier: String
{
case First
case Second
init?(fullType: String)
{
guard let last = fullType.componentsSeparatedByString(".").last else {return nil}
self.init(rawValue: last)
}
var type: String
{
return NSBundle.mainBundle().bundleIdentifier! + ".\(self.rawValue)"
}
}
func handleShortcutItem(shortcutItem: UIApplicationShortcutItem) -> Bool
{
var handled = false
guard ShortcutIdentifier(fullType: shortcutItem.type) != nil else {return false}
guard let shortcutType = shortcutItem.type as String? else {return false}
switch (shortcutType)
{
case ShortcutIdentifier.First.type:
handled = true
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navVC = storyboard.instantiateViewControllerWithIdentifier("sourcesview") as! UINavigationController
if let tabBarController = navVC.topViewController as? UITabBarController {
tabBarController.selectedIndex = 4
}
self.window?.rootViewController?.presentViewController(navVC, animated: true, completion: nil)
break
case ShortcutIdentifier.Second.type:
handled = true
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navVC = storyboard.instantiateViewControllerWithIdentifier("searchview") as! UINavigationController
self.window?.rootViewController?.presentViewController(navVC, animated: true, completion: nil)
break
default:
break
}
return handled
}
You have to set the selectedTab property on your UITabBarController. I assume that the UINavigationController that you load from the nib contains a UITabBarController as top view controller, so after loading the navigation controller from the nib you have to access the tab bar controller and set the selected tab property to the desired tab.
switch (shortcutType)
{
case ShortcutIdentifier.First.type:
handled = true
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navVC = storyboard.instantiateViewControllerWithIdentifier("sourcesview") as! UINavigationController
if let tabBarController = navVC.topViewController as? UITabBarController {
tabBarController.selectedIndex = 1
}
self.window?.rootViewController?.presentViewController(navVC, animated: true, completion: nil)
break
...
}

How to Navigate from one View Controller to another using Swift

I'd like to navigate from one view controller to another. How can I convert the following Objective-C code into Swift?
UIViewController *viewController = [[self storyboard] instantiateViewControllerWithIdentifier:#"Identifier"];
UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:viewController];
[self.navigationController pushViewController:navi animated:YES];
Create a swift file (SecondViewController.swift) for the second view controller
and in the appropriate function type this:
let secondViewController = self.storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as SecondViewController
self.navigationController.pushViewController(secondViewController, animated: true)
Swift 2+
let mapViewControllerObj = self.storyboard?.instantiateViewControllerWithIdentifier("MapViewControllerIdentifier") as? MapViewController
self.navigationController?.pushViewController(mapViewControllerObj!, animated: true)
Swift 4
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "IKDetailVC") as? IKDetailVC
self.navigationController?.pushViewController(vc!, animated: true)
In my experience navigationController was nil so I changed my code to this:
let next = self.storyboard?.instantiateViewControllerWithIdentifier("DashboardController") as! DashboardController
self.presentViewController(next, animated: true, completion: nil)
Don't forget to set ViewController StoryBoard Id in StoryBoard -> identity inspector
If you don't want the back button to appear (which was my case, because I wanted to present after a user logged in) here is how to set the root of the nav controller:
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("YourViewController") as! YourViewController
let navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil)
SWIFT 3.01
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "Conversation_VC") as! Conversation_VC
self.navigationController?.pushViewController(secondViewController, animated: true)
In swift 4.0
var viewController: UIViewController? = storyboard().instantiateViewController(withIdentifier: "Identifier")
var navi = UINavigationController(rootViewController: viewController!)
navigationController?.pushViewController(navi, animated: true)
In Swift 4.1 and Xcode 10
Here AddFileViewController is second view controller.
Storyboard id is AFVC
let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
self.present(next, animated: true, completion: nil)
//OR
//If your VC is DashboardViewController
let dashboard = self.storyboard?.instantiateViewController(withIdentifier: "DBVC") as! DashboardViewController
self.navigationController?.pushViewController(dashboard, animated: true)
If required use thread.
Ex:
DispatchQueue.main.async {
let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
self.present(next, animated: true, completion: nil)
}
If you want move after some time.
EX:
//To call or execute function after some time(After 5 sec)
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
self.present(next, animated: true, completion: nil)
}
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let home = storyBoard.instantiateViewController(withIdentifier: "HOMEVC") as! HOMEVC
navigationController?.pushViewController(home, animated: true);
Swift 3
let secondviewController:UIViewController = self.storyboard?.instantiateViewController(withIdentifier: "StoryboardIdOfsecondviewController") as? SecondViewController
self.navigationController?.pushViewController(secondviewController, animated: true)
In swift 3
let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "NextViewController") as! NextViewController
self.navigationController?.pushViewController(nextVC, animated: true)
let objViewController = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
self.navigationController?.pushViewController(objViewController, animated: true)
Swift 5
Use Segue to perform navigation from one View Controller to another View Controller:
performSegue(withIdentifier: "idView", sender: self)
This works on Xcode 10.2.
Swift 4
You can switch the screen by pushing navigation controller first of all you have to set the navigation controller with UIViewController
let vc = self.storyboard?.instantiateViewController(withIdentifier: "YourStoryboardID") as! swiftClassName
self.navigationController?.pushViewController(vc, animated: true)
In AppDelegate you can write like this...
var window: UIWindow?
fileprivate let navigationCtrl = UINavigationController()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
self.createWindow()
self.showLoginVC()
return true
}
func createWindow() {
let screenSize = UIScreen.main.bounds
self.window = UIWindow(frame: screenSize)
self.window?.backgroundColor = UIColor.white
self.window?.makeKeyAndVisible()
self.window?.rootViewController = navigationCtrl
}
func showLoginVC() {
let storyboardBundle = Bundle.main
// let storyboardBundle = Bundle(for: ClassName.self) // if you are not using main application, means may be you are crating a framework or library you can use this statement instead
let storyboard = UIStoryboard(name: "LoginVC", bundle: storyboardBundle)
let loginVC = storyboard.instantiateViewController(withIdentifier: "LoginVC") as! LoginVC
navigationCtrl.pushViewController(loginVC, animated: false)
}
For Swift 4 & 5 Users can use this way
Swift 5
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
self.navigationController?.pushViewController(vc, animated: true)
Swift 4
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "YourViewController") as? YourViewController
self.navigationController?.pushViewController(vc!, animated: true)
Better practices Swift 5.0
More reusable and readable
Create a protocol
protocol Storyboarded { }
Now create an extension of the protocol
extension Storyboarded where Self: UIViewController {
static func instantiateFromMain() -> Self {
let storyboardIdentifier = String(describing: self)
// `Main` can be your stroyboard name.
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
guard let vc = storyboard.instantiateViewController(withIdentifier: storyboardIdentifier) as? Self else {
fatalError("No storyboard with this identifier ")
}
return vc
}
}
// Make a ViewController extension to use on all of your ViewControllers
extension UIViewController: Storyboarded {}
How to use
let vc = MyViewController.instantiateFromMain()
//here you can pass any data to the next view controller. for example we have a variable with name `myString` in our next view contoller and we want to pass the data my `self viewController`
vc.myString = "This string passed by MyViewController"
self.navigationController?.pushViewController(vc, animated: true)
Note:- You need to give the same identifier on the storyboard as your UIViewController class has. Check the example below
Update for Swift 5:
let next = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.present(next, animated: true, completion: nil)
Don't forget to update the Storyboard ID for both View Controllers!

Resources