SignUp Button Not Working While Handling RootViewController? - ios

I'm building an iOS app using a Storyboard. The root view controller is a Home View Controller. I'm creating the login/logout process, and it's mostly working fine, but I've got a few issues. I need to know the BEST way to set all this up.
When I tap on login and logout the app works fine but when I tap on Sign up Nothing works I have created a navigation controller too.
I'm just not sure what the best method is at this point.
I'm Giving you My Details
This Is MY Switcher Class For Managing View
import UIKit
class Switcher {
static func updateRootViewController() {
let status = UserDefaults.standard.bool(forKey: Constants.kUserDefaults.isSignIn)
var rootViewController : UIViewController?
#if DEBUG
print(status)
#endif
if (status == true) {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBarController = mainStoryBoard.instantiateViewController(withIdentifier: Constants.StoryboardID.homeViewController) as! HomeViewController
rootViewController = mainTabBarController
} else {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let signInViewController = mainStoryBoard.instantiateViewController(withIdentifier: Constants.StoryboardID.signInViewController) as! SignInViewController
rootViewController = signInViewController
}
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = rootViewController
}
}
My App Delegate
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
IQKeyboardManager.shared.enable = true
Switcher.updateRootViewController()
return true
}
Sign UP Button
#IBAction func signUpBtnTapped(_ sender: UIButton) {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
guard let signUpVC = storyBoard.instantiateViewController(withIdentifier: "RegistrationViewController") as? RegistrationViewController else {
return
}
print("Register Tapped")
self.navigationController?.pushViewController(signUpVC, animated: true)
}

The issue is the your rootViewController does not have a UINavigationViewController set up, for neither of the Viewcontrollers.
what you need to do is instead of instantiating like this:
if (status == true) {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBarController = mainStoryBoard.instantiateViewController(withIdentifier: Constants.StoryboardID.homeViewController) as! HomeViewController
rootViewController = mainTabBarController
} else {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let signInViewController = mainStoryBoard.instantiateViewController(withIdentifier: Constants.StoryboardID.signInViewController) as! SignInViewController
rootViewController = signInViewController
}
You need to instantiate a UINavigationController which it's root is these like the following
if (status == true) {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBarController = mainStoryBoard.instantiateViewController(withIdentifier: Constants.StoryboardID.homeViewController) as! HomeViewController
let navigationController = UINavigationController(rootViewController: mainTabBarController)
rootViewController = navigationController
} else {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let signInViewController = mainStoryBoard.instantiateViewController(withIdentifier: Constants.StoryboardID.signInViewController) as! SignInViewController
let navigationController = UINavigationController(rootViewController: signInViewController)
rootViewController = navigationController
}
Now your self.navigationController?.pushViewController(signUpVC, animated: true) will work since the "navigationController" exists.

Related

How to Skip login if user logged already in swift

To skip login if user logged already I am using user defaults and in app delegate I am calling home view controller but the problem is the data is not getting as error coming as nil error Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value in swreal view controller
here my code
if UserDefaults.standard.bool(forKey: "login") {
//YES Already Login
self.window = UIWindow(frame:UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
let navigationController = UINavigationController.init(rootViewController: viewController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
} else {
//NOT Login
self.window = UIWindow(frame:UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "signinpage") as! ViewController
let navigationController = UINavigationController.init(rootViewController: viewController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
and after skiped login to home nil value appearing in this 3rd line. self.view......
super.viewDidLoad()
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
#IBAction func logoutButton(_ sender: Any) {
let alert = UIAlertController(title: "Alert", message: "Are you Sure You want to Logout", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
GIDSignIn.sharedInstance().signOut()
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "signinpage") as! ViewController
UserDefaults.standard.set(false, forKey: "login")
self.navigationController?.setViewControllers([secondViewController], animated: true)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler:nil))
self.present(alert, animated: true, completion: nil)
}
First check your storyboard Id, is that proper or not. And you can check below code for more information. Hope that it may help to solve your problem.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if UserDefaults.standard.object(forKey: "login") != nil {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController: HomeViewController = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
let mainViewController = storyboard.instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
let navigationController = storyboard.instantiateViewController(withIdentifier: "NavigationController") as! NavigationController
navigationController.setViewControllers([viewController], animated: false)
mainViewController.rootViewController = navigationController
let window = UIApplication.shared.delegate!.window!
window!.rootViewController = mainViewController
UIView.transition(with: window!, duration: 0.3, options: [.transitionCrossDissolve], animations: nil, completion: nil)
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
//Check that user login or not
if let isLogin = UserDefaults.standard.object(forKey: "login") as? Bool {
//If already login then show Dashboard screen
self.showDashboardScreen()
} else {
//If not login then show Login screen
self.showLoginScreen()
}
return true
}
func showLoginScreen() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController: LoginViewController = storyboard.instantiateViewController(withIdentifier: "#LoginViewControllerStoryboardID") as! LoginViewController
var navigationController = UINavigationController()
navigationController = UINavigationController(rootViewController: loginViewController)
//It removes all view controllers from the navigation controller then sets the new root view controller and it pops.
window?.rootViewController = navigationController
//Navigation bar is hidden
navigationController.isNavigationBarHidden = true
}
func showDashboardScreen() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let dashboardViewController: DashboardViewController = storyboard.instantiateViewController(withIdentifier: "#DashboardViewControllerStoryboardID") as! DashboardViewController
var navigationController = UINavigationController()
navigationController = UINavigationController(rootViewController: dashboardViewController)
//It removes all view controllers from the navigation controller then sets the new root view controller and it pops.
window?.rootViewController = navigationController
//Navigation bar is hidden
navigationController.isNavigationBarHidden = true
}
According to my observation,
self.revealViewController() is nil. To assure if this is nil, add a breakpoint at the 3rd line and print self.revealViewController() in the console by doing
po self.revealViewController()
if that is nil,
Refer below links:
Self.revealViewController() returns nil
https://github.com/John-Lluch/SWRevealViewController/issues/627
https://www.codebeaulieu.com/programming/2017/5/5/a-cleaner-swrevealviewcontroller-implementation-using-swift-extensions
Also, show the code that you've used to configure SWRevealcontroller.
change this code
self.window = UIWindow(frame:UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
let navigationController = UINavigationController.init(rootViewController: viewController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
to this:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "SWRevealViewController")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
is suposed that you have a navigation controller of typeSWRevealViewController with the segues sw_front to your HomeViewControlleror a NavigationController before it and a sw_rear to your menu VC. so you must instantiate the SWRevealViewController to show the menu, in your code your goint direct to your home screen so the SWRevealViewController is nil because is not been instantiate before the HomeViewController.
PD: here is a sample how i dit in a project and works out the box with the above code
and set this in the identity inspector
You can use multi storyboard concept.
Login Storyboard
Home Storyboard
+(void) LoginHomeScreen:(NSString*)strController andIndex:(int)index
{
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:USERDETAILS];
NSDictionary *userData = [NSKeyedUnarchiver unarchiveObjectWithData:data];
if (userData != NULL && [userData count] > 0) {
//DashboardVC
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Home" bundle:nil];
UINavigationController *navigationController = [storyboard instantiateViewControllerWithIdentifier:#"SideMenuNavigationVC"];
[navigationController setViewControllers:#[[storyboard instantiateViewControllerWithIdentifier:strController]]];
LGSideMenuController *mainViewController = [storyboard instantiateInitialViewController];
mainViewController.rootViewController = navigationController;
UIViewController * SideMenu = [storyboard instantiateViewControllerWithIdentifier:#"SideMenuVC"];
mainViewController.leftViewController = SideMenu;
mainViewController.leftViewPresentationStyle = LGSideMenuPresentationStyleSlideBelow;
UIWindow *window = UIApplication.sharedApplication.delegate.window;
window.rootViewController = mainViewController;
[UIView transitionWithView:window duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil];
} else {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
LoginVC *loginVC = (LoginVC *)[storyboard instantiateViewControllerWithIdentifier:#"LoginVC"];
UINavigationController *navLogin = [[UINavigationController alloc] initWithRootViewController:loginVC];
navLogin.navigationBar.hidden = true;
[[UIApplication sharedApplication].delegate.window setRootViewController:navLogin];
}
}

how can i show specific viewcontroler in notification action?

how can i show specific viewcontroler in notification action?
in appdelegate
func usernotificationcenter(_center: UNUserNotification,didReceive response: UNNotificationPesponse,withCompletionHalndler completion Handler: #escaping () -> Void){
if identifer == "SHOWVIEW_ACTION":
//I want show specific viewController at this
}
func redirectToSpecificVC() {
let mainStoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "versesVC") as UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()}
used these function redirect to specific view controller
Add these Lines of code in did receive response, it worked for me
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = self.window?.rootViewController as? UINavigationController
let destinationController = storyboard.instantiateViewController(withIdentifier: "YourIdentifierName") as? YourViewController
navigationController?.pushViewController(destinationController!, animated: false)
var presentedVC = self.window?.rootViewController
while (presentedVC!.presentedViewController != nil) {
presentedVC = presentedVC!.presentedViewController
}

How to use a IBAction to move from one storyboard to another?

I'm trying to move back to Storyboard Main using an IBAction connected to a UIButton.
In the app delegate is set it up like this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
if doneOnce == false {
doneOnce = true
window?.rootViewController = UIStoryboard.init(name: "Onboarding", bundle: nil).instantiateInitialViewController()
} else {
window?.rootViewController = UIStoryboard.init(name: "Main", bundle: nil).instantiateInitialViewController()
}
return true
}
When i'm in storyboard "Onboarding" I try to get back to storyboard "Main":
These are the 3 code snippets I've tried.
#IBAction func tutorialDone(sender: AnyObject) {
let appDelegateTemp = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegateTemp.window?.rootViewController = UIStoryboard.init(name: "Main", bundle: nil).instantiateInitialViewController()
//let storyboard = UIStoryboard(name: "Main", bundle: nil)
//let vc = storyboard.instantiateInitialViewController()
//showViewController(vc! as UIViewController, sender: self)
//let storyboard = UIStoryboard(name: "Main", bundle: nil)
//let vc = storyboard.instantiateViewControllerWithIdentifier("ViewController") as UIViewController
//presentViewController(vc, animated: true, completion: nil)
}
But when I press the UIButton which trigger tutorialDone I get this error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController tutorialDone:]: unrecognized selector sent to instance
Thanks in advance!
You can initiate a viewcontroller from storyboard by using identifier as :
let storyboard = UIStoryboard(name: "myStoryboardName", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("nextViewController") as UIViewController
presentViewController(vc, animated: true, completion: nil)
Don't forget to give ID to your nextViewController
Refer this_link

LoginViewController whose view is not in the window hierarchy! in Appldelegate

My goal is to check if there is a token in the keychain, if there isn't then simply show a login view controller screen. The problem right now, is that I get this error. I wrote this code in AppDelegate.swift
.LoginViewController: 0x7ff59b619820> on whose view is not in the window hierarchy!
Here's the code
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let keychain = Keychain(server: "https://app.herokuapp.com", protocolType: .HTTPS)
if ((try? keychain.contains("token")) != nil) {
showLoginScreen()
} else {
}
return true
}
func showLoginScreen() -> Void {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let setViewController = mainStoryboard.instantiateViewControllerWithIdentifier("loginView") as! LoginViewController
let rootViewController = self.window!.rootViewController
rootViewController?.presentViewController(setViewController, animated: false, completion: nil)
}
try this
add self.window.makeKeyAndVisible() before present
self.window.makeKeyAndVisible()
Update
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let setViewController = mainStoryboard.instantiateViewControllerWithIdentifier("loginView") as! LoginViewController
self.window.makeKeyAndVisible()
self.window!.rootViewController.presentViewController(setViewController, animated: false, completion: nil)
for additional information see this
By setting your view controller as UINavigationControllers rootviewcontroller and then adding navigationcontroller as Windows rootviewcontrollers will work check out the modified code below:
func showLoginScreen() -> Void {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewControllerWithIdentifier("loginView") as UIViewController
let navigationController = UINavigationController(rootViewController: vc)
self.window!.rootViewController = navigationController
self.window!.makeKeyAndVisible()
}
If you like to switch between two viewcontrollers depending on the LoginStatus i suggest you to follow the below method:
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
if LofinStatus == true{
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewControllerWithIdentifier("My_Offer") as UIViewController
let navigationController = UINavigationController(rootViewController: vc)
self.window!.rootViewController = navigationController
}else{
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Login", bundle: nil)
let vc = mainStoryboard.instantiateViewControllerWithIdentifier("loginView") as UIViewController
let navigationController = UINavigationController(rootViewController: vc)
self.window!.rootViewController = navigationController
}
self.window!.makeKeyAndVisible()
NOTE: In the above code i had used two storyboards Main and Login
It worked for me perfectly,give it a try and let me know the result.Thank You

How to get Current viewcontroller (currently Presenting) using storyboard id in swift programmatically?

**How to get the presenting view controller in swift. I am using storyboard id.**And for presenting next viewcontroller how can I add to the hierarchy?
I tried like this:
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let logincontroller = mainStoryboard.instantiateViewControllerWithIdentifier("LoginViewController")
if UIApplication.sharedApplication().keyWindow?.rootViewController.presentingViewController == logincontroller {
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let nextVC = mainStoryboard.instantiateViewControllerWithIdentifier(storayboardIdentifier)
self.presentViewController(nextVC, animated: true, completion: nil)
}
In Appdelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if isLoggedin == false {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
else {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
}
The code works, it display the view but it still have a warning
Failed to instantiate the default view controller for
UIMainStoryboardFile 'Main' - perhaps the designated entry point is
not set?
Check initial entry points.
Also to present screen below code practice is better way.
let objNextViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ID_NextViewController") as? ViewController
self.presentViewController(objNextViewController, animated: true) { () -> Void in
print("Achive")
}
EDITED :
If you want to present viewcontroller from already presented view controller then use below code.
var currentViewController : UIViewController!
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
if let viewControllers = appDelegate.window?.rootViewController?.presentedViewController
{
self.currentViewController = viewControllers as UIViewController
}
else if let viewControllers = appDelegate.window?.rootViewController?.childViewControllers
{
self.currentViewController = viewControllers.last! as UIViewController
}
let objNewViewController : NewViewController!
self.currentViewController.presentViewController(objNewViewController!, animated: true, completion: { () -> Void in
NSLog("Achived")
})
try this code for presentingViewControllerusing storyboard name:
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController") as UIViewController
self.presentViewController(viewController, animated: false, completion: nil)
try this code,
let storyboard : UIStoryboard = UIStoryboard(name:"Main", bundle: nil)
let vc : WelcomeViewController = storyboard.instantiateViewControllerWithIdentifier("WelcomeID") as WelcomeViewController
let navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil)
hope its helpful
My guess is that you haven't set an initial view controller for your storyboard.
To fix this open your storyboard and select the UIViewController you want to display as the first one. Then in the Attributes inspector tab(third one from the right in the utilities panel), look under the View Controller section and make sure the Is Initial View Controller checkbox is checked.

Resources