Perform segue on completion of web service call Swift3 - ios

I am trying to perform a segue on successful login in swift 3. Once my web service returns success message I want to perform segue. I am trying the same in the following manner:
DispatchQueue.main.sync(execute: {
print("Login successful")
self.performSegue(withIdentifier: "goToTimerPage", sender: self)
})
My log is printing fine.
Please help me with this. I am new to web services.

use like this
DispatchQueue.main.sync(execute: {
print("Login successful")
self.performSegue(withIdentifier: "goToTimerPage", sender: self)
})
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToTimerPage" {
//present your view controller or do some code
}

Simple way for navigation.
Setup your didFinishLaunchingWithOptions like this way.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let storyboard :UIStoryboard
if UIDevice.currentDevice().userInterfaceIdiom == .Pad{
storyboard = UIStoryboard(name: "Main_iPad", bundle: nil)
}
else{
storyboard = UIStoryboard(name: "Main", bundle: nil)
}
let navigationController:UINavigationController = storyboard.instantiateInitialViewController() as! UINavigationController
let objLoginViewController:UIViewController = storyboard.instantiateViewControllerWithIdentifier("ID_LoginViewController") as! LoginViewController
navigationController.viewControllers = [objLoginViewController]
if self.window != nil {
self.window!.rootViewController = navigationController
}
return true
}
Call this function once get successful response.
self.redirectToNewViewcontroller()
Code for redirectToNewViewcontroller function
func redirectToNewViewcontroller()
{
let objNewViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ID_NewViewController") as? NewViewController
self.navigationController?.pushViewController(objNewViewController!, animated: true)
}

simply make sure you embed your view controller in a navigation controller
the source view controller not the destination view controller

Related

How do I dismiss a rootViewController before presenting a new UITabBarController?

I've set up a UIViewController as my rootViewController in AppDelegate, however, when a user logs in or skips it I am presenting a UITabBarController over the top.
I need to dismiss the LoginController, and set the UITabController as rootViewController instead after user logs in.
How can I go about reorganizing this?
AppDelegate()
window = UIWindow()
window?.makeKeyAndVisible()
window?.rootViewController = LoginController()
LoginController()
self.present(MainTabBarController(), animated: true, completion: nil)
you can design your code like this.
This one
It's too easy to maintain condition for user logged in or not, and then based on that status. You can navigate to your view.
You can try this way :
1.In AppDelegate you can these methods.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let isLogin = UserDefaults.standard.bool(forKey: "IS_LOGIN")
if isLogin == true {
self.goToDashboardView()
} else {
self.goToLoginView()
}
return true
}
//MARK:- ------- Global Methods -------
class func sharedInstance() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
func goToLoginView() {
let sb = UIStoryboard.init(name: "Main", bundle: nil)
let loginVC = sb.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
let navVC = UINavigationController(rootViewController: loginVC) // You can skip this if you do not want to add navigation bar
self.window?.rootViewController = navVC // if you skipped above line, then you have to assign 'loginVC' here.
self.window?.makeKeyAndVisible()
}
func goToDashboardView() {
let sb = UIStoryboard.init(name: "Main", bundle: nil)
let tabbarVC = sb.instantiateViewController(withIdentifier: "MyTabBarController") as! MyTabBarController
self).window?.rootViewController = tabbarVC // if you skipped above line, then you have to assign 'loginVC' here.
self.window?.makeKeyAndVisible()
}
2.In LoginViewController, when user logged in successfully.
#IBAction func btnLoginClicked(_ sender: UIButton) {
// Your API call or other code
// If all things goes well, then login and go to dashboard
UserDefaults.standard.set(true, forKey: "IS_LOGIN")
AppDelegate.sharedInstance().goToDashboardView()
}
3.And finally, whenever and from wherever you want to log out from app, just call below code.
#IBAction func btnLogOutClicked(_ sender: UIButton) {
// Your API call or other code
// If all things goes well, then logout and go to login view
UserDefaults.standard.set(false, forKey: "IS_LOGIN")
AppDelegate.sharedInstance().goToLoginView()
}
4.And Main.storyboard should have design something like :
you do not need to present the UITabBarViewController and then dismiss the LoginViewController, you just need to reset the UITabBarViewController as a rootViewController for you app after login or skip as the following:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
// Override point for customization after application launch.
let yourTabBar = UIStoryboard(name: "YOUR_STORYBOARD_NAME", bundle: nil).instantiateViewController(withIdentifier: "YOUR_UITABBARCONTROLLER_ID")
self.window!.rootViewController = yourTabBar
self.window!.makeKeyAndVisible()
return true
}

Prepare for segue function using SW revealer

I'm trying to send a bool through a SWRevealViewControllerSeguePushController using prepareForSegue function, but it doesn't even gives me a response.
This code is in my side menu viewController (sw_rear). I've also set an identifier on the segue and this is my code so far:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "registerSegue" {
if let loginVC = segue.destination as? LoginVC {
print("Set it as true")
loginVC.registerActivated = true
}
} else {
if let loginVC = segue.destination as? LoginVC {
print("set it as false")
loginVC.registerActivated = false
}
}
}
I'm not receiving any output to the console with this code. Is there another good way to send data between ViewControllers using SWRevealViewControllerSeguePushController on a segue?
Thanks!

Swift segue not working?

My Swift segue is not working at all and isn't throwing any errors. The breakpoint shows me that the app lands on this line but nothing happens:
self.performSegueWithIdentifier("SignupSegue", sender: self)
The code block is a login form with Facebook:
if let accessToken: FBSDKAccessToken = FBSDKAccessToken.currentAccessToken() {
PFFacebookUtils.logInInBackgroundWithAccessToken(result.token, block: {
(user: PFUser ? , error : NSError ? ) - > Void in
if user!.isNew {
self.performSegueWithIdentifier("SignupSegue", sender: self)
} else {
self.navigateToInGame(true)
}
})
}
Here's the segue function it should call, but doesn't even get to it:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "SignupSegue") {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("SignUpViewController")
self.showViewController(vc, sender: self)
}
}
Any ideas?
Generally, any UI updating has to be in main thread. I think the block for PFFacebookUtils.logInInBackgroundWithAccessToken is still in the background state in above situation. Maybe trigger the showViewController in dispatch_async(dispatch_get_main_queue(), {}) and see if there is any difference.
dispatch_async(dispatch_get_main_queue(), {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("SignUpViewController")
self.showViewController(vc, sender: self)
})
Ok. I just tried it out. Hope you did all the things regarding StoryBoard Reference.
Me too had the same issue with performSegueWithIdentifier.
Example:
Let take two storyboard main and signup.
1) In main.storyboard create a storyboard reference. Set the storyboardId in the Storyboard Reference as signup and the referencedId as the storyboardId of the scene(viewController) which is in signup.storyboard. Look at this link for a clear picture Storyboard to Storyboard
2) Set the segue identifier between viewController and Storyboard Reference in main.storyboard
3) Since I faced the same problem with performSegueWithIdentifier, I replaced it with shouldPerformSegueWithIdentifier.
override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
if(identifier == "segue_identifier"){
// segue_identifier is the viewController and storyBoard Reference segue identifier.
print("hello")
}
return true;
}
Let me know if you find any issues. It did work for me.
Performing a segue leads to present a new view controller.You don't need to and can't create and show view controller in prepareForSegue.It will look like:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "SignupSegue") {
let vc = segue.destinationViewController
}
}
Swift 3 solved:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "SignupSegue") {
DispatchQueue.main.async {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "SignUpViewController")
self.show(vc, sender: self)
}
}
}
You can try this ...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "SignupSegue") {
if let destination = segue.destination as? SignUpViewController {
...
}
}
}
The closest I can get to overcome same problem for myself:
Made trigger var segueLogin : Bool = false with initialised value in the Class.
When PFFacebookUtils gets needed values for segue, change trigger to true:
PFFacebookUtils.logInInBackground(withReadPermissions: permissions) {
(user: PFUser?, error: Error?) -> Void in
if let user = user {
if user.isNew {
print("User signed up and logged in through Facebook!")
self.segueLogin = true
} else {
print("User logged in through Facebook!")
self.segueLogin = true
}
} else {
print("Uh oh. The user cancelled the Facebook login.")
self.loginCancelledLabel.alpha = 1
}
}
Then added code to viewDidAppear class. Realised it starts everytime PFFacebookUtils complete. So it checks if returned value is true and performs segue after successful PFFacebookUtils session:
override func viewDidAppear(_ animated: Bool) {
if segueLogin == true {
self.performSegue(withIdentifier: "segueSingup", sender: self)
}
}

Choose which view to load when app runs in Swift

I would like to know which is the best way to do this and how to implement it:
When the app runs, it checks if there's a value in user defaults
NSUserDefaults.standardUserDefaults().valueForKey("uid") == nil If the value is nil, I would like the app to redirect to a view called LoginViewController, and if not nil, go to MainViewController. Both clases are UIViewController.
I was thinking in create a new RedirectViewController as initial View Controller, and check it there, but it doesn't work, it doesn't redirects:
class RedirectOnStart: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if NSUserDefaults.standardUserDefaults().valueForKey("uid") == nil {
self.performSegueWithIdentifier("loginRegisterSegue", sender: nil)
} else {
self.performSegueWithIdentifier("mainViewSegue", sender: nil)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "loginRegisterSegue" {
let nav = segue.destinationViewController as! LoginRegisterViewController
}
if segue.identifier == "mainViewSegue" {
let nav = segue.destinationViewController as! ViewController
}
}
}
If your scenario starts with "when the app runs" you should consider working in the AppDelegate's didFinishLaunchingWithOptions directly.
For example:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow()
if NSUserDefaults.standardUserDefaults().valueForKey("uid") == nil {
self.window?.rootViewController = LoginController()
} else {
self.window?.rootViewController = MainController()
}
self.window?.makeKeyAndVisible()
return true
}
Found that the above answer is written for Objective-C not Swift; currently written it won't load up the actual view controller you want. Below code will work within 'didFinishLaunchingWithOptions".
make sure you have a userdefault (in my case "Username") for the statement to check for. If it find it's empty; that'll direct you to "SignUpVC", if it's not empty, it'll direct you to "LoginVC".
you'll need to ensure you have set your identifiers for your View Controllers on your storyboard (in my case, 'Main').
after this, make sure you have some sort of method setup to go from Login/Signup to the next set of screens, such as a segue.
Hope this helps someone out there, Have a great day.
Swift 3:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
self.window = UIWindow()
if UserDefaults.standard.value(forKey: "Username") == nil {
let signupViewCon = storyboard.instantiateViewController(withIdentifier: "SignUpVC")
self.window?.rootViewController = signupViewCon
} else {
let loginViewCon = storyboard.instantiateViewController(withIdentifier: "LoginVC")
self.window?.rootViewController = loginViewCon
}
self.window?.makeKeyAndVisible()
return true
}

iOS Login Screen Modal on top of Tab Bar or Instantiated

I am developing an iOS App that has several Tabs. So I decided my root view Controller will be a Tab Bar Controller with 2 views.
I need the user to login as soon as the application starts, so I'm trying to find out the best approach to do this.
Following other similar questions posted here I've tried this 2 approaches:
Presenting the login screen as a Modal View on top of the Tab Bar Controller
Instantiating the Login view controller
I've done this, by using a UserisLoggedIn flag in NSUserDefaults that is set every time the user logs in or logs out.
The problem I face with both approaches is that before the login screen appears there's a quick flickr of the first view in the Tab Bar.
I've tried to resolve this setting the alpha value of the Tab Bar to 0 if the user is not logged in for the modal approach, but for the instance approach it doesnt work, it still flickers before showing the login screen. Anyway, I find this solution tedious and not really elegant.
There must be a standard approach for doing this in iOS, since you have loads of apps that present first a login screen, but since I am a beginner with iOS Programming I still don't know how to do it.
Here's some code from my Tab bar controller:
1st Approach
Tab Bar Controller
override func viewDidLoad() {
super.viewDidLoad()
view.alpha = 0
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") as NSString == "loggedIn"{
view.alpha = 1.0
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(false)
self.showLoginView()
}
func showLoginView(){
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
self.performSegueWithIdentifier("loginView", sender: self)
}
}
Login View Controller
func updateUserLoggedInFlag() {
// Update the NSUserDefaults flag
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("loggedIn", forKey: "userLoggedIn")
defaults.synchronize()
}
#IBAction func login(sender: AnyObject) {
//Do my login here...
//If login successful:
self.performSegueWithIdentifier("dismissLogin", sender: self)
}
2nd Approach, Creating an Instance of the Login View Controller
1st View in the Tab Bar
override func viewDidAppear(animated: Bool){
super.viewDidAppear(true)
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
let loginController: LoginViewController = self.storyboard?.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController
self.tabBarController?.presentViewController(loginController, animated: false, completion: nil)
}
Login View Controller
#IBAction func login(sender: AnyObject) {
//Do my login here...
//If login successful:
self.dismissViewControllerAnimated(true, completion: nil)
}
OK here is what did the trick for me. I don't know if it's the right thing to do, but it seems to work. Like Joseph Duffy mentioned all I did was to set the Login view as the rootviewcontroller in the delegate, and once I was succesfully logged in, switch back to the tab bar controller as rootviewcontroller.
Code in AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
showLogin()
}
}
func showLogin() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController
self.window?.makeKeyAndVisible()
self.window?.rootViewController = loginViewController
}
Code in LoginViewController
#IBAction func login(sender: AnyObject) {
//Do my login here...
//If login successful:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
self.dismissViewControllerAnimated(true, completion: nil)
appDelegate.window?.rootViewController = storyboard.instantiateViewControllerWithIdentifier("tabBarID") as TabBarController
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
showLoginView()
}
func showLoginView(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController: LoginViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController
self.window?.makeKeyAndVisible()
self.window?.rootViewController?.presentViewController(loginViewController, animated: true, completion: nil)
}
Take a look at a similar question's answer. The solution is to do this check in your app delegate's application:didFinishLaunchingWithOptions: method by checking if the user is logged in and loading the login view from a storyboard when necessary.
I have created a blank project, added a view controller with a storyboard identifier of loginScreen and have the following code in the app delegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
self.showLogin()
return true
}
func showLogin() {
//loginScreen
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController = storyboard.instantiateViewControllerWithIdentifier("loginScreen") as UIViewController
if let window = self.window {
window.makeKeyAndVisible()
window.rootViewController?.presentViewController(loginViewController, animated: false, completion: nil)
}
}
This shows the login screen and the main screen is not seen.

Resources