Swift, Firebase - Present different ViewControllers in AppDelegate if User is Logged-in - swift

I'm using Firebase for my app and I want to present different view controllers in AppDelegate with the code below but I keep getting an error.
import UIKit
import Firebase
import FirebaseAuth
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow()
if Auth.auth().currentUser != nil {
window?.rootViewController = HomeController()
} else {
window?.rootViewController = LoginController()
}
return true
}
...
This is the error.
libc++abi.dylib: terminating with uncaught exception of type
NSException
(lldb)
How can I fix this problem?

Swift 4.0
You can use this function as like below in AppDelegate.
func configureWindowAndMakeVisible(rootVC: UIViewController) {
if let app = UIApplication.shared.delegate as? AppDelegate, let window = app.window {
window.rootViewController = rootVC
window.makeKeyAndVisible()
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if Auth.auth().currentUser != nil {
// Use initialization (i.e HomeController()) only if you had initialize view in Controller
configureWindowAndMakeVisible(rootVC: HomeController())
} else {
configureWindowAndMakeVisible(rootVC: LoginController())
}
return true
}

First of all, you need to know that you need a reference to the already created instance instead of creating a new one. There can be two case
Case 1. If you want to change the initial view controller on the check of if Auth.auth().currentUser == nil or iAuth.auth().currentUser != nil then you can simply write the code in didFinishLaunchingWithOptions in AppDelegate and make sure you must give the identifier in storyboard and use the same identifier in the code
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let mainView = UIStoryboard(name: "MainStoryboard", bundle: nil)
if Auth.auth().currentUser != nil {
let viewcontroller : MainViewController = mainView.instantiateViewController(withIdentifier: "MainViewIdentifier") as! MainViewController
self.window!.rootViewController = viewcontroller
self.window?.makeKeyAndVisible();
} else {
let viewcontroller : LoginViewController = mainView.instantiateViewController(withIdentifier: "loginViewIdentifier") as! LoginViewController
self.window!.rootViewController = viewcontroller
self.window?.makeKeyAndVisible();
}
return true
}
Case 2. Suppose you have Main/Home/Dash VC (View controller) and it’s always is the initial view controller then there you have implemented the check if Auth.auth().currentUser == nil then present/push the Login view controller else not.

You are Direct Creating New Instance of ViewController
Try the following code
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if Auth.auth().currentUser != nil {
var mainView: UIStoryboard!
mainView = UIStoryboard(name: "MainStoryboard", bundle: nil)
let viewcontroller : HomeController = mainView.instantiateViewController(withIdentifier: "someViewController") as! HomeController
self.window!.rootViewController = viewcontroller
self.window?.makeKeyAndVisible();
} else {
var mainView: UIStoryboard!
mainView = UIStoryboard(name: "MainStoryboard", bundle: nil)
let viewcontroller : LoginController = mainView.instantiateViewController(withIdentifier: "loginVCIdentifier") as! LoginController
self.window!.rootViewController = viewcontroller
self.window?.makeKeyAndVisible();
}
return true
}
Make Sure you have given identifier to controller from storyboard

Related

How to call particular storyboard on app launch based on device type (iphone/ipad)?

I have two separate storyboards for iPad and iPhone, they have the same classes, outlets and etc, but different layouts.
I found that I can detect device type on app launch with UIScreen.main.traitCollection.userInterfaceIdiom, but now I need to call correct storyboard. How do I do that? Am I even on the right direction? All I found related to this problem is like posts made 8-9 years ago so I don't even understand syntax sometimes.
Thanks in advance!
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let iPhoneStoryboard = UIStoryboard(name: "IPhone", bundle: nil)
let iPadStoryboard = UIStoryboard(name: "IPad", bundle: nil)
let type = UIScreen.main.traitCollection.userInterfaceIdiom
switch type {
case .phone:
// need to call something here
case .pad:
// need to call something here
#unknown default:
fatalError()
}
You have to instantiate the view controller by instantiateInitialViewController() or instantiateViewController(withIdentifier:)
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let iPhoneStoryboard = UIStoryboard(name: "IPhone", bundle: nil)
let iPadStoryboard = UIStoryboard(name: "IPad", bundle: nil)
let type = UIScreen.main.traitCollection.userInterfaceIdiom
switch type {
case .phone:
window?.rootViewController = iPhoneStoryboard.instantiateInitialViewController()
case .pad:
window?.rootViewController = iPadStoryboard.instantiateInitialViewController()
#unknown default:
fatalError()
}
window?.makeKeyAndVisible()
}
}
HII can you try to set instantiateViewController to UINavigationController and set identifier like as "Ipad" or "Iphone" and set first controller of storyboard to rootviewcontroller of UINavigationController and set initial viewcontrolled to UINavigationController like as...
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let iPhoneStoryboard = UIStoryboard(name: "IPhone", bundle: nil)
let iPadStoryboard = UIStoryboard(name: "IPad", bundle: nil)
let type = UIScreen.main.traitCollection.userInterfaceIdiom
switch type {
case .phone:
if let IPhone = iPhoneStoryboard.instantiateViewController(withIdentifier: "IPhone") as? UINavigationController {
self.window?.rootViewController = IPhone
}
case .pad:
if let IPad = iPadStoryboard.instantiateViewController(withIdentifier: "IPad") as? UINavigationController {
self.window?.rootViewController = IPad
}
#unknown default:
fatalError()
}
self.window?.makeKeyAndVisible()
self.window?.makeKey()
return true
}

Error: Missing return in a closure expected to return 'UIViewController' (Xcode, Swift, iOS 13)

I'm getting the error: "Missing return in a closure expected to return 'UIViewController'" on the bolded line. How can I fix this? Thank you!!
Var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let hasSession = UserDefaults.standard.value(forKey: "UserHasSubmittedPassword") as? Bool
let vc: UIViewController = {
if let hasSession = hasSession, hasSession == true {
// next vc you want to show
} else {
// enter password vc
}
**}()**
let navigationController = UINavigationController(rootViewController: vc)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
return true
}
you just need to return ViewController inside closure
Var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let Myvc = UIViewController()
let hasSession = UserDefaults.standard.value(forKey: "UserHasSubmittedPassword") as? Bool
let vc: UIViewController = {
if let hasSession = hasSession, hasSession == true {
// next vc you want to show
return Myvc
} else {
// enter password vc
return Myvc
}
**}()**
let navigationController = UINavigationController(rootViewController: vc)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
return true
}

Appdelegate sigabrt not appearing anything ! in main storyboard

I am making a newsfeed and when I try to add a post it appears this alert[SIGABRT]and not go to the next viewController to write the post here it's a picture , any idea?
and those are some ss from the breakpoint and exception.
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let authListener = Auth.auth().addStateDidChangeListener { auth, user in
let storyboard = UIStoryboard(name: "Main", bundle: nil )
if user != nil {
UserService.observeUserProfile(user!.uid) { UserProfile in
UserService.currentUserProfile = UserProfile
}
//
let controller = storyboard.instantiateViewController(withIdentifier: "MainTabBarController") as! UITabBarController
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
} else {
UserService.currentUserProfile = nil
let controller = storyboard.instantiateViewController(withIdentifier: "MenuViewController") as! ViewController
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
}
}
return true
}
}

Changed from Navigation to TabBar, CoreData does not load

I changed my Navigation Controller to Tab Bar Controller, then I wanted to compile the app. But it does not load my managedContext anymore.
This is my launching code when I load the app:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
guard let navController = window?.rootViewController as? UINavigationController,
let viewController = navController.topViewController as? ViewController else {
return true
}
viewController.managedContext = coreDataStack.managedContext
// Override point for customization after application launch.
return true
}
Therefore I tried to edit the code like this:
Edit:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateInitialViewController()
//let controller = storyboard.instantiateViewController(withIdentifier: "TabBarVC")
self.window?.rootViewController = controller
guard let tabController = window?.rootViewController as? UITabBarController,
let navController = tabController.viewControllers![0] as? UINavigationController,
let viewController = navController.topViewController as? ViewController else {
return true
}
// Version that works for UINavigationCOntroller
// guard let navController = window?.rootViewController as? UINavigationController,
// let viewController = navController.topViewController as? ViewController else {
// return true
// }
viewController.managedContext = coreDataStack.managedContext
// Override point for customization after application launch.
return true
}
I changed the code, but I still can not load managedContext, and it returns nil when I want to use it in ViewController, I also set the initial Viewcontroller to the tabBarController.
Set rootviewcontroller for your window first and then right your logic afterwards.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let storyboard = UIStoryboard(<StoryboardName>, bundle: nil)
let controller = storyboard.initializeInitialViewController()
window.rootViewController = controller
guard let navController = window?.rootViewController as? UITabBarController,
let viewController = navController.moreNavigationController as? ViewController else {
return true
}
viewController.managedContext = coreDataStack.managedContext
// Override point for customization after application launch.
return

how to passing coredatastack from AppDelegate to the view controller without navigation controller

I know the way to pass coreDataStack to the viewController with navigation controller embedded by this way.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let navigationController = window!.rootViewController as! UINavigationController
let viewController = navigationController.topViewController as! ViewController
viewController.coreDataStack = coreDataStack
return true
}
I want to pass the coreDataStack to my viewController without the navigation controller,
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewControllerWithIdentifier("Home") as! Home
viewController.coreDataStack = coreDataStack
return true
}
However, the coreDataStack in the viewController found to be nil.
How can I do it?
Your code is creating a new instance of the view controller, not referencing the existing instance. You should be able to use this:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let viewController = window!.rootViewController as! ViewController
viewController.coreDataStack = coreDataStack
return true
}