Once a user signs in to my app, I need to take them to a tab view controller so they can use the app to its fullest potential. I have tried to initiate the TabBarController in the buttons onClick function with no success.
PFUser.logInWithUsernameInBackground(username, password:password) {
(user: PFUser?, error: NSError?) -> Void in
if error == nil {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("KlikurHomeTabs") as! UITabBarController
self.presentViewController(vc, animated: true, completion: nil) // this shows it modally
} else if error!.code == 101 {
var invalidLogin:UIAlertView = UIAlertView(title: "Please try again", message: "The username password combo you have us does not match our records, please try again or reset your password.", delegate: self, cancelButtonTitle: "Try again")
invalidLogin.show()
}
}
Can anybody spot what I am doing wrong? I have no clue and have been trying for a while now. Thanks :)
Just change this line and also take out the storyboard line of code
let vc = storyboard.instantiateViewControllerWithIdentifier("KlikurHomeTabs") as! UITabBarController
To
let vc = self.storyboard.instantiateViewControllerWithIdentifier("KlikurHomeTabs")
self.presentViewController(vc!, animated: true, completion: nil)
This is more of an elaboration on Paulw11's comment, but here is what I am doing. I have a "splash" view controller that has 2 storyboard segues, one to a signin/signup view controller, and one to my main tabview controller. Inside viewDidAppear, I check the login status and then perform one of the two segues. Here is an example of the code.
override func viewDidAppear(animated: Bool) {
if needsLogin {
performSegueWithIdentifier("SignIn/SignUP", sender: self)
} else {
performSegueWithIdentifier("MainTabBar", sender: self)
}
}
Related
I have one scenario when the user did not use the application for more than 5 min app will show a popup with session expiration message.
The code for session expiration is added in the appDelegate and from there the popup will be presented on the current view controller.
code is
#objc func applicationDidTimeout(notification: NSNotification) {
if (window?.rootViewController?.isKind(of: UITabBarController.self))! {
for view in window?.rootViewController?.view.subviews ?? [(window?.rootViewController?.view)!] {
if view.isKind(of: MBProgressHUD.self) {
return
}
}
if window?.rootViewController?.presentedViewController != nil {
window?.rootViewController?.dismiss(animated: true, completion: {
self.showMessage(message: Message.sessionTimeout)
})
} else {
self.showMessage(message: Message.sessionTimeout)
}
}
}
fileprivate func showMessage(message: String) {
let alert = UIAlertController(title: appName, message: message, preferredStyle: .alert)
let actionOkay = UIAlertAction(title: "OK", style: .default) { (action) in
DispatchQueue.main.async {
UIView.transition(with: self.window!, duration: 0.3, options: UIView.AnimationOptions.transitionCrossDissolve, animations: {
CommonFunctions.setLoginAsRootVC()
}, completion: nil)
}
}
alert.addAction(actionOkay)
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
Now if the user is doing some data entry and at that time, if the user leaves application ideal for 5 min or more the keyboard will dismiss and the session expiration message shown there.
But as the text field's delegate method textFieldShouldEndEditing has some validation and if that validation fails it shows a popup with the message and ok button.
So when the user taps on the ok button in the session expiration message popup, it will redirect the user to the login screen but due to the text field's delegate method validation, it shows one pop up in the login screen.
Code for the validation fail message popup is
fileprivate func showErrorMessage(message: String) {
let alert = UIAlertController(title: appName, message: message, preferredStyle: .alert)
let actionOkay = UIAlertAction(title: "OK", style: .default) { (action) in
self.txtField.becomeFirstResponder()
}
alert.addAction(actionOkay)
self.present(alert, animated: true, completion: nil)
}
How to prevent the popup from being present in the login screen?
I try to get the proper way to prevent the popup from appearing on the login screen.
But Finally, I found one heck to solve this issue.
I have declared one boolean in AppDelegate and set it's value to false when I want to prevent the popup from appearing and then revert it back to true when I want to show the popup.
I know this is not the elegant or efficient solution for the issue, but it works for now.
If anyone knows the better answer can post here, I'm still open to any better solution.
#objc func applicationDidTimeout(notification: NSNotification)
{
let visibleView : UIViewController = self.getVisibleViewControllerFrom(self.window?.rootViewController)!
self.showMessage(message: Message.sessionTimeout,Controller: visibleView)
}
fileprivate func showMessage(message: String , Controller : UIViewController) {
let alert = UIAlertController(title: appName, message: message, preferredStyle: .alert)
let actionOkay = UIAlertAction(title: "OK", style: .default) { (action) in
//Now apply your code here to set login view controller as rootview
// This controller is for demo
window!.rootViewController = UIStoryboard(name: "Main", bundle:
nil).instantiateViewController(withIdentifier: "loginview")
window!.makeKeyAndVisible()
}
alert.addAction(actionOkay)
Controller.present(alert, animated: true, completion: nil)
}
//MARK:- Supporting method to get visible viewcontroller from window
func getVisibleViewControllerFrom(_ vc: UIViewController?) -> UIViewController? {
if let nc = vc as? UINavigationController {
return self.getVisibleViewControllerFrom(nc.visibleViewController)
} else if let tc = vc as? UITabBarController {
return self.getVisibleViewControllerFrom(tc.selectedViewController)
} else {
if let pvc = vc?.presentedViewController {
return self.getVisibleViewControllerFrom(pvc)
} else {
return vc
}
}
}
Try this code, I've use this code many times may be it's work for you.
I am trying to write a login process for my app. I have embedded a navigation controller to HomeViewController and set it as the initial ViewController. How can I fix it such that when a user enters the wrong credentials the HomeViewController will not be shown at all?
This is what it is doing:
Correct credentials entered
Display LoginViewController -> User inputs credentials -> Display HomeViewController
Wrong credentials entered
Display LoginViewController -> User inputs credentials -> Display HomeViewController -> Display LoginViewController
Code for LoginViewController (look at the last block of code)
func handlingAuthentication(notification: NSNotification) {
let dict = notification.object as! NSDictionary
if dict["error"]! as! Bool == true {
let errorMessage = dict["message"] as! String
//initialize Alert Controller
let alertController = UIAlertController(title: "Authentication error", message: errorMessage, preferredStyle: .Alert)
//Initialize Actions
let okAction = UIAlertAction(title: "Ok", style: .Default){
(action) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}
//Add Actions
alertController.addAction(okAction)
//Present Alert Controller
self.presentViewController(alertController, animated: true, completion: nil)
}
else
{
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isUserLoggedIn")
NSUserDefaults.standardUserDefaults().synchronize()
self.dismissViewControllerAnimated(true, completion:nil)
}
}
Code for HomeViewController
override func viewDidAppear(animated: Bool) {
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if(!isUserLoggedIn){
self.performSegueWithIdentifier("toLoginVC", sender: self)
}
}
UPDATE
I've tried placing the code block in ViewDidLoad but I am still getting the same issue (in fact now I'm stuck on the homePage)
override func viewDidLoad() {
super.viewDidLoad()
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if(!isUserLoggedIn){
self.performSegueWithIdentifier("toLoginVC", sender: self)
}
usernameLabel.text = Data.sharedInstance.userName
getTaskDetails()
displayTask.dataSource = self
}
If the main view controlled decides and displays the login you will inevitable see it on screen because it's already in the process of displaying - so it shouldn't do it. You should have some other controller, perhaps a splash view controller, which decides to show either the login or the main view.
In your login view controller the alert OK button calls dismiss, this is the reason the login controller disappears and re-appears again (after showing the main controller for a short time).
I have that error when I want open new view and I don't know what does it mean.
I run that code:
func openMenu(){
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: UIViewController = storyboard.instantiateViewControllerWithIdentifier("MenuViewController") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
And the error is:
Warning: Attempt to present on whose view is not in the window hierarchy!
I have that Swift code:Swift
And I want execute with Objective-C the Swift code.
Objective-C
replace the line:
self.presentViewController(vc, animated: true, completion: nil)
with:
dispatch_async(dispatch_get_main_queue(), {
self.presentViewController(vc, animated: true, completion: nil)
})
See if it works!
or
why don't you create a segue and call it using:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "Load View") {
// pass data to next view
}
}
I'm attempting a simple sign out function where the view returns to my login/sign up view after the user signs out. I have tried using these two methods, but the application crashes every time.
First Method:
#IBAction func signPressed(sender: AnyObject) {
PFUser.logOut()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! UIViewController
presentViewController(vc, animated: true, completion: nil)
}
Second Method:
I created the following function:
func loginSetup() {
if (PFUser.currentUser() == nil) {
let vc = ViewController()
self.presentViewController(vc, animated: true, completion: nil)
}
}
then added it to my sign out function:
#IBAction func signPressed(sender: AnyObject) {
PFUser.logOut()
self.loginSetup()
}
both crashed and gave me an app delegate error.. whats the issue here?
here is screenshot of error given :
https://40.media.tumblr.com/1f044ecbdd5059836b0a360d16af9846/tumblr_nqzsobll0o1tupbydo1_1280.png
Providing you've set the root VC to the Login/Sign Up screen.
func didTapSignOut(sender: AnyObject)
{
PFUser.logOut()
self.navigationController?.popToRootViewControllerAnimated(true)
}
Then you can call this function in a UIButton IBAction but I call it on my UINavigationBar like so,
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .Plain, target: self, action: "didTapSignOut:")
I have the following IBActions on my navigation bar
#IBAction func logoutPressed(sender: AnyObject) {
SweetAlert().showAlert("Are you sure?", subTitle: "Do you really want to logout?", style: AlertStyle.Warning, buttonTitle:"Cancel", buttonColor:UIColorFromRGB(0xD0D0D0) , otherButtonTitle: "Yep", otherButtonColor: UIColorFromRGB(0xDD6B55)) { (isOtherButton) -> Void in
if isOtherButton == false {
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64( Double(NSEC_PER_SEC) * 4.0 ))
SwiftSpinner.show("Logging out")
dispatch_after(popTime, dispatch_get_main_queue(), {
PFUser.logOut()
self.performSegueWithIdentifier("logoutSegue", sender: nil)
SwiftSpinner.hide()
})
}
else {
}
}
}
//OPTIONS MENU
#IBAction func optionsPressed(sender: AnyObject) {
let alert = SCLAlertView()
alert.addButton("Submit Feedback"){
var subjectText = "feedback"
var toRecipient = ["some email address"]
var mc:MFMailComposeViewController = MFMailComposeViewController()
mc.mailComposeDelegate = self
mc.setSubject(subjectText)
mc.setToRecipients(toRecipient)
self.presentViewController(mc, animated: true, completion: nil)
}
alert.addButton("About") {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("about") as UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
and so on....
And this works perfectly fine when I launch the app to the view controller containing these IBActions.
However, the problem is when I perform a modal/push transition into the said view controller, the IBAction's aren't being called....
Any ideas?
I just dealt with this issue too, may not be a general solution as for me it was a silly mistake, but the issue was that i had changed the class of the 'view' inside my ViewController:
The highlighted view was named something else until i changed it back to UIView in the identity inspector:
Hope that helps you, or someone else :)