I try to explain situation:
I have two view controllers: viewHome and viewStartTest.
When student start app first time, don't have any data about his test in table.
In this situation should be display viewStartTest controller after launch screen.
But when he start app again and condition "test is finished" is true, viewHome controller should be display at start.
I try to put this code in AppDelegate.swift and simulate finished test but still not working, thanks for help:
// 0 - false, 1 - True
var conditionTest = 1
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if conditionTest == 1 {
self.window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewStartTest: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "viewStartTest")
self.window?.rootViewController = viewStartTest
self.window?.makeKeyAndVisible()
} else {
self.window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let ViewHome: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "viewHome")
self.window?.rootViewController = ViewHome
self.window?.makeKeyAndVisible()
}
}
Correct Scene delegate code after discussion below:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
if conditionTest == 1 {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewStartTest: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "viewStartTest")
self.window?.rootViewController = viewStartTest
self.window?.makeKeyAndVisible()
} else {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let ViewHome: UIViewController = mainStoryboard.instantiateViewController(withIdentifier: "viewHome")
self.window?.rootViewController = ViewHome
self.window?.makeKeyAndVisible()
}
}
guard let _ = (scene as? UIWindowScene) else { return }
}
You need to store the value of conditionTest somewhere. I would suggest using UserDefaults . This is an example of how you could implement it:
NavigationController:
class MainNavigationControllerViewController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
if isLoggedIn() {
let homeController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "HomeVC")
viewControllers = [homeController]
}
}
fileprivate func isLoggedIn() -> Bool {
return UserDefaults.standard.isLoggedIn()
}
}
Extension for UserDefaults:
extension UserDefaults {
func setIsLoggedIn(value: Bool) {
set(value, forKey: "isLoggedIn")
synchronize()
}
func isLoggedIn() -> Bool {
return bool(forKey: "isLoggedIn") }
}
How to use:
with the above code you can simply login/logout the user. Make sure to call .synchronize()
Login:
UserDefaults.standard.setIsLoggedIn(value: true)
UserDefaults.standard.synchronize()
Logout:
UserDefaults.standard.setIsLoggedIn(value: false)
UserDefaults.standard.synchronize()
Related
I am showing onboard view but i want to show once thats working othervise when user sing in i want to show main tab this code every time showing sign in screen. can you help me to solution.
Thank you
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let currentUser = Auth.auth().currentUser
let userDefaults = UserDefaults.standard.bool(forKey: "hasLaunched")
let onboardSB = UIStoryboard(name: "Onboarding", bundle: nil)
let mainSB = UIStoryboard(name: "Main", bundle: nil)
var vc: UIViewController
if userDefaults {
if currentUser != nil {
let board = UIStoryboard(name: "Main", bundle: nil)
let tabBar = board.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController
window?.rootViewController = tabBar
} else {
vc = mainSB.instantiateViewController(identifier: "SignInNav")
}
}
else{
vc = onboardSB.instantiateViewController(identifier: "OnBoardingVC")
}
UserDefaults.standard.set(true, forKey: "hasLaunched")
self.window?.rootViewController = vc
I have a question.
in "class SceneDelegate"
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
let url = userActivity.webpageURL
print(url) //result is www.mywebsite.com
}
how can I pass this url to my ViewController???
It'll depend on the view controller hierarchy you have, but let's say you have a UITapBarController as your root view controller and you want to eventually get to a view controller that's within a navigation controller:
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
let url = userActivity.webpageURL
if let windowScene = scene as? UIWindowScene {
for window in windowScene.windows {
if let rootViewController = window.rootViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let yourVC = storyboard.instantiateViewController(withIdentifier: "YourVC") as? YourViewController,
let tabBarController = rootViewController as? UITabBarController,
let navController = tabBarController.selectedViewController as? UINavigationController {
yourVC.data = url
navController.pushViewController(yourVC, animated: true)
}
}
}
}
}
Update
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
let url = userActivity.webpageURL
if let windowScene = scene as? UIWindowScene {
for window in windowScene.windows {
if let rootViewController = window.rootViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let yourVC = storyboard.instantiateViewController(withIdentifier: "EventViewController") as? EventViewController,
let navController = rootViewController as? UINavigationController {
yourVC.data = url
navController.pushViewController(yourVC, animated: true)
}
}
}
}
}
I do have a non-Storyboard, 100% coded UIViewController, UICollectionView and UICollectionViewCell - works perfect.
here's the code in question:
SceneDelegate
not sure if this is relevant, tho.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let myController = MyViewController(collectionViewLayout: layout)
window?.rootViewController = myController
window?.makeKeyAndVisible()
}
.
.
ViewController
very simple and straight forward...
class MyViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let data = loadOnboardingData()
.
.
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .white
collectionView?.register(MyPageCell.self, forCellWithReuseIdentifier: "cellId")
collectionView?.isPagingEnabled = true
collectionView.showsHorizontalScrollIndicator = false
collectionView?.tag = myPageControl.currentPage
setupMyPageControl()
}
ViewControllerExtention
here's the problem: the pushViewController method just doesn't do anything but the modal present works like a charm and I'm not getting what's wrong and why:
extension MyViewController: MyPageCellDelegate {
.
.
func didTabOnActionButton(title: String) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
guard let homeViewController = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as? HomeViewController else {
print("Coun't find controller")
return
}
navigationController?.pushViewController(homeViewController, animated: true) <- NO EFFECT
//present(homeViewController, animated: true, completion: nil) <- WORKS PERFECT!
}
MyPageCell
I set up the Delegate via protocol and it seems that's fine too
protocol MyPageCellDelegate {
func didTabOnActionButton(title: String)
}
class MyPageCell: UICollectionViewCell {
var delegate: MyPageCellDelegate?
let myActionButton: UIButton = {
let button = UIButton(type: .system)
return button
}()
myActionButton.addTarget(self, action: #selector(self.doAction), for: .touchUpInside)
.
.
#objc private func doAction(_ sende: Any) {
delegate?.didTabEndOnboardingActionButton(title: "end Onboarding")
}
so, any Idea what's wrong with:
navigationController?.pushViewController(homeViewController, animated: true)
EDIT --------------------------------------------------------------------
As pointed out by #Michcio this here: window?.rootViewController = UINavigationController(rootViewController: myController) works half way and as far as I understand it, I'm embedding myController into an UINavigationController which adds the Navigation Bar to the current and following controllers.
But that's not what I need!
What I need is a clean and simple one for the onboarding i.e. MyViewController and the HomeViewController should be one with a Tab- and Navigation Bar
Basically starting from scratch after onboarding.
I used to solve this in the previous version editing the AppDelegate first Method like this (in this example I used Storyboards):
extension AppDelegate {
func showOnboarding() {
if let window = UIApplication.shared.keyWindow, let onboardingViewController = UIStoryboard(name: "Onboarding", bundle: nil).instantiateInitialViewController() as? OnboardingViewController {
onboardingViewController.delegate = self
window.rootViewController = onboardingViewController
}
}
func hideOnboarding() {
if let window = UIApplication.shared.keyWindow, let mainViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() {
mainViewController.view.frame = window.bounds
UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: {
window.rootViewController = mainViewController
}, completion: nil)
}
}
}
and in the Delegate itself like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let isFirstRun = true // logic to determine goes here
if isFirstRun {
showOnboarding()
}
return true
}
but I'm seriously not getting the new SceneDelegate or simply don't understand it
Really would appreciate if someone could past some code here for re-use.
It didn't work, because you are set MyViewController as window.rootViewController. Just change line in SceneDelegate to:
window?.rootViewController = UINavigationController(rootViewController: myController)
I have few view controllers embedded in UINavigationController. The first view controller is login page. The second view controller is the home page. I want initialview controller as second view controller when the user is already logged in.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
// Override point for customization after application launch.
if let data = Locksmith.loadDataForUserAccount(userAccount: "someString")
{
if let userAccessToken = data["accessToken"]
{
if (userAccessToken as! String) != ""
{
let initialViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "HomePageViewController") as! HomePageViewController
loginResponse = LoginResponse()
loginResponse?.UserAccessToken = userAccessToken as? String
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
}
}
return true
}
The problem is the subsequent view controllers are not embedded in navigation controller. Since it is not embedded in navigation controller I am not able to goback from one view controller to the other.
Add this in App delegate
first check user already login or not, if login then execute this code
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let redViewController = mainStoryBoard.instantiateViewControllerWithIdentifier("respectiveIdentifier") as! ViewController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = redViewController
Use this in App Delegate and add an extension of UIStoryboard.
func checkForAlreadyLogin() {
let dashBoardScreen = UIStoryboard.dashBoardScreen()
let loginController = UIStoryboard.loginController()
if UserDefaults.standard.bool(forKey: UserDefaultValues().LOGINSTATUS){
self.window!.rootViewController = dashBoardScreen
}else {
self.window!.rootViewController = loginController
}
}
public extension UIStoryboard {
class func mainStoryboard() -> UIStoryboard { return UIStoryboard(name: "Main", bundle: Bundle.main) }
class func dashBoardScreen() -> HomeViewController?{
return mainStoryboard().instantiateViewController(withIdentifier: "HomeViewController") as? HomeViewController
}
internal class func loginController() -> LoginViewController?{
return mainStoryboard().instantiateViewController(withIdentifier: "LoginViewController") as? LoginViewController
}
}
Just call this checkForAlreadyLogin() method in 'didFinishLaunchingWithOptions'.
Also remember to set StoryboardID in the storyboard for each viewController.
This code did the trick for me.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
if let data = Locksmith.loadDataForUserAccount(userAccount: "someString")
{
if let userAccessToken = data["accessToken"]
{
if (userAccessToken as! String) != ""
{
let initialViewController = UIStoryboard(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "HomePageViewController") as! HomePageViewController
let navigationController = self.window?.rootViewController as! UINavigationController
navigationController.pushViewController(initialViewController, animated: true)
}
}
}
return true
}
I have a PageViewController with 3 views to present the app, on the last page I have a button linked with my TabBarViewController.
I would like to have only for the first launch, my 3 views of presentation and then for the next launched, start directly with my TabBarViewController.
How can I do it?
Thanks!!!
EDIT
tabBarController :
required init(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)!
}
Button between page views and tabBar :
#IBAction func firstTime() {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "hasAppBeenLaunchedBefore")
print(true)
}
AppDelegate :
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
didFinishLaunchingOnce()
return true
}
func didFinishLaunchingOnce() -> Bool
{
let defaults = NSUserDefaults.standardUserDefaults()
if let hasBeenLauncherBefore = defaults.stringForKey("hasAppBeenLaunchedBefore")
{
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var exampleViewController: TabBarViewController = mainStoryboard.instantiateViewControllerWithIdentifier("TabBarViewController") as! TabBarViewController
self.window?.rootViewController = exampleViewController
self.window?.makeKeyAndVisible()
//print(" N-th time app launched ")
return true
}
else
{
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var exampleViewController: OnboardingPager = mainStoryboard.instantiateViewControllerWithIdentifier("OnboardingPager") as! OnboardingPager
self.window?.rootViewController = exampleViewController
self.window?.makeKeyAndVisible()
//print(" First time app launched ")
defaults.setBool(true, forKey: "hasAppBeenLaunchedBefore")
return false
}
}
Enjoy