How to skip 2 ViewController correctly - ios

Tell me, please, what am I doing wrong?
There are 3 View:
The user selects his gender
The user enters his weight
Main View Application
After the user has written this data, he gets to the main screen of the application. I want to make the user choose his gender and weight only at the very first launch of the application. To do this, I created a UserSettings model to store the entered values there:
final class UserSettings {
enum SettingsKeys: String {
case userSex
case userWeight
}
static var userSex: String! {
get {
return UserDefaults.standard.string(forKey: SettingsKeys.userSex.rawValue)
}
set {
let defaults = UserDefaults.standard
let key = SettingsKeys.userSex.rawValue
if let sex = newValue {
print("Пол \(sex) добавлен в \(key)")
defaults.set(sex, forKey: key)
} else {
defaults.removeObject(forKey: key)
}
}
}
static var userWeight: String! {
get {
return UserDefaults.standard.string(forKey: SettingsKeys.userWeight.rawValue)
}
set {
let defaults = UserDefaults.standard
let key = SettingsKeys.userWeight.rawValue
if let weight = newValue {
print("Вес \(weight) добавлен в \(key)")
defaults.set(weight, forKey: key)
} else {
defaults.removeObject(forKey: key)
}
}
}
}
In AppDelegate in function didFinishLaunchingWithOptions launchOptions wrote:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let defaults = UserDefaults.standard
let skipPageSex = defaults.bool(forKey: UserSettings.userSex)
let skipPageWeight = defaults.bool(forKey: UserSettings.userWeight)
if skipPageSex && skipPageWeight == true {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let nextView: MainViewController = mainStoryboard.instantiateViewController(identifier: "MainViewController") as! MainViewController
window?.rootViewController = nextView
self.window?.makeKeyAndVisible()
} else {
let firstStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let firstView: WelcomeViewController = firstStoryboard.instantiateViewController(identifier: "welcomeVC") as! WelcomeViewController
window?.rootViewController = firstView
self.window?.makeKeyAndVisible()
}
return true
}
In the Sex select View in the button action, I wrote:
#IBAction func manSelected(_ sender: UIButton) {
sender.setTitle("Male", for: .normal)
UserSettings.userSex = sender.currentTitle
let defaults = UserDefaults.standard
defaults.setValue(true, forKey: UserSettings.userSex)
defaults.synchronize()
}
And the same for the button with the female choice, only sender.setTitle("Female", for: .normal)
I tried removing UIMainStoryboardFile and UIApplicationSceneManifest in Info.plist and in this case I get just a black screen without errors. In the Storyboard ID I use the same value as in AppDelegate. Please, help

Try something like this. Initial with a TempViewController. Depend on your data, it will segue perform show Gender Picker or go directly to Main. Remember to check the Is Initial View Controller for root Navigation Controller.

Related

Once i Login why i am not getting HomeViewController as Rootviewcontroller in Swift?

In appdelegate i am getting UserId.. means i am login but when i run second time i am not getting homeviewcontroller as rootviewcontroller why? still it shows phonenumviewcontroller
navigationcontroller -> phonenumviewcontroller -> registrationiewcontroller -> homeviewcontroller
In storyboard navigationcontroller is initialviewcontroller
In registrationviewcontroller i am getting userId which i have saved in keychain.
I dont have signout button so i have written code like below in registrationiewcontroller
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String:AnyObject]
print("terms and condition JSON \(json)")
let jsonObj: String = json["Success"] as? String ?? ""
if jsonObj == "true" {
let userID: String=jsonObj?["userId"] as? String ?? ""
DispatchQueue.main.async {
KeychainWrapper.standard.set(userID, forKey: "USERID")
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController;
UserDefaults.standard.set("NoLogout", forKey:"Signout")
self.navigationController?.pushViewController(viewController, animated: true);
}
}
}
no signout button so added this code in registrationviewcontroller
UserDefaults.standard.set("NoLogout", forKey:"Signout")
this code in appdelegate: getting userId but still homeviewcontroller is not coming as rootviewcontroller, only phonenumviewcontroller is coming why?
var savedUserId: String?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
savedUserId = KeychainWrapper.standard.string(forKey: "USERID")
KeychainWrapper.standard.set(savedUserId ?? "", forKey: "PersonalID")
print("appdelegate userid \(savedUserId)")
logOutString = UserDefaults.standard.string(forKey: "Signout") as NSString? ?? "" as NSString
if logOutString.isEqual(to: "NoLogout") {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyBoard = UIStoryboard.init(name: "Main", bundle: nil)
let viewcontroller = storyBoard.instantiateViewController(withIdentifier: "HomeViewController")
let navigationController = UINavigationController(rootViewController: viewcontroller)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
else {
}
return true
}
once registration is completed i need rootviewcontroller as homeviewcontroller... how to get that, please help me with code
From whatever I've gathered, here's what you need to do:
In AppDelegate:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let isUserLoggedIn = UserDefaults.standard.bool(forKey: "isUserLoggedIn") // Give you own check to see if user is logged in
window = UIWindow()
window?.makeKeyAndVisible()
let viewController = isUserLoggedIn ? MainViewController() : LoginViewController()
window?.rootViewController = UINavigationController(rootViewController: viewController)
return true
}
}
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(handleUserLoggedOut))
}
#objc func handleUserLoggedOut() {
UserDefaults.standard.set(false, forKey: "isUserLoggedIn")
UIApplication.shared.keyWindow?.rootViewController = UINavigationController(rootViewController: LoginViewController())
}
}
class LoginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Login", style: .plain, target: self, action: #selector(handleUserLoggedIn))
}
#objc func handleUserLoggedIn() {
UserDefaults.standard.set(true, forKey: "isUserLoggedIn")
UIApplication.shared.keyWindow?.rootViewController = UINavigationController(rootViewController: MainViewController())
}
}
This is only a skeleton. Give both controller different background colours and button action to call handleUserLoginIn and handleUserLoggedOut on respective controllers and see how it works. Play around with it and figure out.
Note: keyWindow is deprecated so you need to use this instead at all places.
let keyWindow = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
Edit: I've also added the login, logout buttons and set backgroundColors for you to see for yourself the result.

NSUserDefault Value found nil with kill the App

I just trying to save the user Id and status as true value in UserDefaults when they login or Register with App.
UserDefaults.standard.set(user?.CustID, forKey: "CustID")
UserDefaults.standard.set(true, forKey: "status")
so when the user reopen the app in my Appdelegate I check the Status if it's true then user directly pass on HomeScreen and if the status False its pass on login screen.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let status = UserDefaults.standard.bool(forKey: "status")
if (status == true) && (custID != "") {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "HomeTicketViewController") as! HomeTicketViewController
let navigationController = UINavigationController(rootViewController: nextViewController)
let appdelegate = UIApplication.shared.delegate as! AppDelegate
appdelegate.window!.rootViewController = navigationController
}else {
let storyBoard : UIStoryboard = UIStoryboard(name: "Login", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
let navigationController = UINavigationController(rootViewController: nextViewController)
let appdelegate = UIApplication.shared.delegate as! AppDelegate
appdelegate.window!.rootViewController = navigationController
}
}
I get the status true but i found that The CustID found nil.
Is there any solution for that?
In userdefault if value not found in userdefaults corresponding to key then userdefault return nil and in case of bool it returns false.
In your case, when you app launches, app does not have any value corresponding to custID so you getting nil.
You need to add check like this
if (status == true) && (custID != nil){
:
:
}
The default is false
let status = UserDefaults.standard.bool(forKey: "status")
so status will be false at first , also status being true doesn't mean CustID saved no nil
UserDefaults.standard.set(user!.CustID, forKey: "CustID")
as user may be nil so force-unwrap to verify that

Swift UIBarButtonItem is hidden but works

I have an problem with an UIBarButtonItem. If I protect my app with an ViewController, to authenticate the User through Touch ID, then the UIBarButtonItem in the Navigation Controller is hidden.
The code in the AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let touchIDonoff = UserDefaults.standard.object(forKey: "touchIDActive") as! Bool!
if touchIDonoff == true {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC = storyboard.instantiateViewController(withIdentifier: "TouchIDViewController") as! TouchIDViewController
self.window?.rootViewController = loginVC
}
return true
}
Code in the ViewController for TouchID-Request:
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.async {
self.touchIDrequest()
}
#IBAction func buttonTouchID(_ sender: AnyObject) {
touchIDabfrage()
}
func touchIDrequest() {
let authenticationContext = LAContext()
var error: NSError?
if authenticationContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
authenticationContext.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Please authenticate", reply: { (success: Bool, error: Error?) in
if success {
self.navigatetoAuthenticatedVC()
} else {
if let evaluateError = error as? NSError {
print(error)
/*let message = self.errorMessageForLAErrorCode(errorCode: evaluateError.code)
self.showAlertViewAfterEvaluatingPolicyWithMessage(message: message)
*/
}
}
})
} else {
showAlertViewForNoBiometrics()
return
}
}
func navigatetoAuthenticatedVC() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "LoggedInVC") as! UITabBarController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
DispatchQueue.main.async {
appDelegate.window?.rootViewController = tabBarController
}
}
If I hit the hidden UIBarButtonItem it works and bring me to the next ViewController and when I go back, the UIBarButtonItem is visible.
What did I wrong? Any help please?
Best regards

Back button disappears after creating AppDelegate in Swift 3.0

I created the structure as below in xcode 8 swift 3.0.
Before I add AppDelegate code. Back button still appear fine on Apply, Apply Behalf and Profile controller.
I use segue to open page.
But after I add AppDelegate code into Homepage and Login controllers , back button disappears on Apply, Apply behalf and profile controller page.
Can someone help or explain why is this happening ? How to enable back the back button on apply, apply behalf and profile page ?
Thanks.
Home.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet var staffNumberLbl: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
staffNumberLbl.text = UserDefaults.standard.object(forKey: "login") as? String
}
override func viewDidAppear(_ animated: Bool) {
let isUserLoggedIn = UserDefaults.standard.bool(forKey: "loggedIn")
if(!isUserLoggedIn){
self.performSegue(withIdentifier: "loginview", sender: self)
}
}
#IBAction func logoutData(_ sender: Any) {
UserDefaults.standard.set(false, forKey: "loggedIn")
UserDefaults.standard.synchronize();
let loginViewController = self.storyboard!.instantiateViewController(withIdentifier: "loginview") as! LoginViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = loginViewController
appDelegate.window?.makeKeyAndVisible()
}
}
Login.swift
import UIKit
class LoginViewController: UIViewController {
#IBOutlet var loginlbl: UITextField!
#IBOutlet var passlbl: UITextField!
#IBOutlet var login_button: UIButton!
var login: String!
var pw: String!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func loginData(_ sender: Any) {
login = loginLbl.text
pw = passLbl.text
if(login == "" || pw == ""){
return
}
else{
let url = URL(string: "http://localhost/login.php")
let session = URLSession.shared
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
let LoginDataToPost = "login=\(login!)&pw=\(pw!)"
request.httpBody = LoginDataToPost.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
if error != nil {
return
}
else {
do {
if let json = try JSONSerialization.jsonObject(with: data!) as? [String: String]
{
DispatchQueue.main.async
{
let message = Int(json["message"]!)
let login = json["login"]
if(message == 1) {
UserDefaults.standard.set(true, forKey: "isUserLoggedIn")
UserDefaults.standard.set(login, forKey: "login")
UserDefaults.standard.synchronize();
self.dismiss(animated: true, completion: nil)
let myViewController:ViewController = self.storyboard!.instantiateViewController(withIdentifier: "ViewController") as! ViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = myViewController
appDelegate.window?.makeKeyAndVisible()
print("Value for login is : \(login!)")
return
}
else {}
}
}
else {}
}
catch let jsonParse {}
}
})
task.resume()
}
}
}
AppDelegate.swift
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let mainStoryBoard: UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let isUserLoggedIn:Bool = UserDefaults.standard.bool(forKey: "isUserLoggedIn")
if(!isUserLoggedIn) {
let loginViewController = mainStoryBoard.instantiateViewController(withIdentifier: "loginview") as! LoginViewController
window!.rootViewController = loginViewController
window!.makeKeyAndVisible()
}
else {
let homePage = mainStoryBoard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
window!.rootViewController = homePage
window!.makeKeyAndVisible()
}
return true
}
}
You are setting rootviewcontroller without embedding navigation controller to it in logoutData & loginData function.
Use this code :
let navigationController = UINavigationController.init(rootViewController: myViewController)
appDelegate.window?.rootViewController = navigationController
Use this code in AppDelegate:
if(!isUserLoggedIn) {
let loginViewController = mainStoryBoard.instantiateViewController(withIdentifier: "loginview") as! LoginViewController
let navigationController = UINavigationController.init(rootViewController: loginViewController)
appDelegate.window?.rootViewController = navigationController
window!.makeKeyAndVisible()
}
else {
let homePage = mainStoryBoard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
let navigationController = UINavigationController.init(rootViewController: homePage)
appDelegate.window?.rootViewController = navigationController
window!.makeKeyAndVisible()
}
Remove this from Home.swift,
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = loginViewController
appDelegate.window?.makeKeyAndVisible()
because its not inheriting the properties of Navigation controller
and add it in Appdelegate.swift file
For the other 3 viewcontrollers, you need to add the Navigation controller between eachSegway in order to inherit it or code the button by instantiating the viewcontrollers respectively
After successful login,try to make NavigationController as rootViewController instead of your ViewController
Your back button will start appearing.
In AppDelegate, in else block, instead of this line
let homePage = mainStoryBoard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
write this
let homePage = mainStoryBoard.instantiateViewController(withIdentifier: "NavigationController") as! UINavigationController
Inside LoginViewController, in the block if(message == 1)
replace
let myViewController:ViewController = self.storyboard!.instantiateViewController(withIdentifier: "ViewController") as! ViewController
with
let navController:UINavigationController = self.storyboard!.instantiateViewController(withIdentifier: "NavigationController") as! UINavigationController
Also set storyboard identifier for UINavigationController in storyboard to NavigationController
Depending on your configuration:
self.navigationItem.hidesBackButton = YES;
OR:
self.navigationController.navigationItem.hidesBackButton = YES;
Or, if you just want to disable the button without hiding it, you can use this.
self.navigationController.navigationItem.backBarButtonItem.enabled = NO;

check if user is logged in ios swift

i want check in appdelegate.swift file if user logged in showing HomeviewController like Instagram and if not Showing LoginViewController , iam using mysql to save users data and php bridge lang
code in appdalegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
var rootViewController = self.window!.rootViewController
let isUserLoggedIn:Bool = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if(isUserLoggedIn) {
let mainStoryboard = UIStoryboard(name: "Main" , bundle: nil)
let protectedPage = mainStoryboard.instantiateViewControllerWithIdentifier("goToHome") as! HomeViewController
window!.rootViewController = protectedPage
window!.makeKeyAndVisible()
}
else{
let mainStoryboard = UIStoryboard(name: "Main" , bundle: nil)
let loginViewController = mainStoryboard.instantiateViewControllerWithIdentifier("loginview") as! LoginViewController
window!.rootViewController = loginViewController
window!.makeKeyAndVisible()
}
return true
}
loginviewcontoler.swift
let success:NSInteger = jsonData.valueForKey("success") as! NSInteger
//[jsonData[#"success"] integerValue];
NSLog("Success: %ld", success);
if(success == 1)
{
NSLog("Login SUCCESS");
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
prefs.setObject(username, forKey: "USERNAME")
prefs.setInteger(1, forKey: "ISLOGGEDIN")
prefs.synchronize()
self.performSegueWithIdentifier("goToHome", sender: self)
ProfileViewController.swift
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
let isLoggedIn:Int = prefs.integerForKey("ISLOGGEDIN") as Int
if (isLoggedIn != 1) {
self.performSegueWithIdentifier("goto_login", sender: self)
}
else
{
self.usernameLabel.text = prefs.valueForKey("USERNAME") as? String
}
}
sorry for long question
Don't use in this situation NSUserDefaults
https://github.com/matthewpalmer/Locksmith
Here is good example of using safe LogIn / LogOut
so, after implementation
if let dictionary = Locksmith.loadDataForUserAccount("accaunt")
{
//go to profile
}
else
{
//go to login
}
Follow step:-
Step 1 :- Create custom SplashViewController set rootViewController SplashViewController
Step 2 :- Write login service call on SplashViewController
Setp 3 :- When you get Login success then just change rootViewController
Setp 4 :- Write one method in AppDelegate For change rootViewController for redirect Homescreen.
Setp 5 :- Call AppDelegate method for go to Homescreen.
You have to do some works.
1. You have to make sure that the user is logged in. to do that when you press the button (login button) use UserDefaults
let userDefault = UserDefaults.standard
userDefault.set(true, forKey: "isLoggedIn")
userDefault.synchronize()
2.When user will launch the app again just check whether the user logged in or not in viewDidAppear method/ viewDidLoad(its your choice which method you will use. most of the time I use viewDidAppear)
let userDefault = UserDefaults.standard
let savedData = userDefault.bool(forKey: "isLoggedIn")
if(savedData){
performSegue(withIdentifier: "segueTest", sender:nil)//here u have decide the which view will show if the user is logged in how. here i used segue.
}else{
viewController = self// this is the main view. just make the object of the class and called it.
}
I hope you know how to prepare segue
Just a concise way of doing the same thing:
func checkIfUserIsLoggedIn() {
if Auth.auth().currentUser == nil {
DispatchQueue.main.async {
// present login controller
let loginVC = LoginVC()
let navController = UINavigationController(rootViewController: loginVC)
self.present(navController, animated: true, completion: nil)
}
return
}
}

Resources