How to perform the Segue only after authorization with Touch ID - swift

Maybe someone can help, just want to use Segue for Login button to made a transfer to second ViewController only after authorization with Touch ID but application still performing the Segue after user pressing on the button.
import UIKit
import LocalAuthentication
class LoginWindowViewController: UIViewController {
#IBAction func loginButton(_ sender: Any) {
let context: LAContext = LAContext()
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil){
context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: "For login you need to use your TouchID", reply: {(wasSuccessful, error) in if wasSuccessful {
DispatchQueue.main.async {
self.shouldPerformSegue(withIdentifier: "LoginComplete", sender: self.navigationController)
}
}else{
print ("Bad TouchID")
}
})
}
}
Thanks

Try implementing this function and checking from where it's being called:
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
}
Remember that as you're calling the segue from your code, if you have already added a segue action from your button to the next ViewController in the storyboard you should remove it and only create a connection between your LoginViewController to the one you want to call

As the documentation states, if you do not override the shouldPerformSegue method, the default implementation returns true for all segues.
The shouldPerformSegue(withIdentifier:sender:) method should determine whether a segue with the specified identifier will or will not be called depending on the return value of your implementation.
Since you already check whether the TouchID authorization was successful, you don't actually need to call shouldPerformSegue, but rather you need to call performSegue.
context.evaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, localizedReason: "For login you need to use your TouchID", reply: {(wasSuccessful, error) in
if wasSuccessful {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "LoginComplete", sender: self.navigationController)
}
}else{
print ("Bad TouchID")
}
})

Related

Is there a way to perform a conditional segue in a swift ViewController?

I am attempting to authenticate user sign in using Firebase. If a user's credentials are verified, I am seguing to the home screen of my application within an if-else statement using user and error. However, performSegue(...) executes whether or not the log in actually occurred.
I am certain that the problem is not with verification/login/logout issues in Firebase or with the textfields.
Here is my code:
func handleSignIn(username:String, password:String) {
Auth.auth().signIn(withEmail: username, password: password) { user, error in
if error == nil && user != nil {
//self.dismiss(animated: false, completion: nil)
print("Logged in!")
self.performSegue(withIdentifier: "toHome", sender: nil)
} else {
print("Error logging in: \(error!.localizedDescription)")
}
}
}
Best,
Code Daddy
I have solved this issue.
The code above is actually correct and functional. The issue was that the handleSignIn method was called within:
#IBAction func didTapLogin(_ sender: Any) {...}
That button itself was the segue connection with the identifier "toHome," and so regardless of what the if/else block evaluated to, the application proceeded to the home menu.
Once I deleted and reestablished the segue "toHome" from the LoginViewController to the HomeViewController (not the Log In button to the HomeViewController), this code worked properly.

open other view with segue only works by pressing button

I want to open an other view controller, after checking if it is the first run of the app.
It works when I press a button but not when I call the method openMap
class TutorialController: UIViewController {
override func viewDidLoad() {
//check if the app opens for the first time
if(UserDefaults.standard.bool(forKey: "HasLaunchedOnce"))
{
// app already launched
print("not first launch")
openMap()
}
else
{
// This is the first launch ever
UserDefaults.standard.set(true, forKey: "HasLaunchedOnce")
UserDefaults.standard.synchronize()
print("first launch")
openTutorial()
}
}
func openTutorial(){
}
#IBAction func openMap(){
print("openmap opened")
performSegue(withIdentifier: "openMap", sender: nil)
}
}
I assume, you've connected your button to #IBAction func openMap()
if so, you should not call openMap() action inside your viewDidLoad, but use the same code performSegue(withIdentifier: "openMap", sender: nil) instead in your viewDidAppear:
if(UserDefaults.standard.bool(forKey: "HasLaunchedOnce"))
{
// app already launched
print("not first launch")
performSegue(withIdentifier: "openMap", sender: nil)
}
...
If it doesn't work, you've probably made a mistake with creation of your segue and have connected Button to the destination ViewController directly in your storyboard instead of connecting two controllers:
If so, just remove the old segue, and re-crete it in the way as it is on the image above and assign the same segue id "openMap"
EDITED:
Please, move performing of your segue to the viewDidAppear instead of viewDidLoad, because viewDidLoad is called when the ViewController object is created and it's not yet attached to the window.
Ok, from what I understand is that you want to perform a segue "openMap" when it HasLaunchedOnce. Well what you're doing wrong is that you're calling an #IBAction func. This is my suggestion
if you still want to have that button
create a function and name if whatever you want. Inside this function perform this segue. Link this function to the if else statement and the button.
eg:
//if else statement
if(UserDefaults.standard.bool(forKey: "HasLaunchedOnce"))
{
// app already launched
print("not first launch")
anotherFunction()
}
//#ibaction (scrap this if you don't want the button)
#IBAction func openMap()
{
print("openmap opened")
anotherFunction()
}
//another function
func anotherFunction()
{
performSegue(withIdentifier: "openMap", sender: nil)
}
hope this helps

how to segue to 2nd page from successful login - "warning attempt to present on while a presentation is in progress" error

How do I segue to my 2nd page after successfully verifying login?
I have pulled a segue from the login page view controller (not the login button) to the next page and named the segue 'nextPage'. (If I segue from the login button then the button click allows all logins to segue through without testing them). When I segue from the login page it correctly checks details but does not segue to the next page on successful login, and instead I get the console error "Warning: Attempt to present on while a presentation is in progress!"
the code is
#IBAction func loginButtonTapped(sender: AnyObject) {
let userEmail = userEmailTextField.text;
let userPassword = userPasswordTextField.text;
let userEmailStored = NSUserDefaults.standardUserDefaults().stringForKey("userEmail");
let userPasswordStored = NSUserDefaults.standardUserDefaults().stringForKey("userPassword");
if userEmailStored == userEmail && userPasswordStored == userPassword {
// Login successful
// Display an alert message
displayMyAlertMessage("Login successful. Thank you");
NSUserDefaults.standardUserDefaults().setBool(true,forKey:"isUserLoggedIn");
NSUserDefaults.standardUserDefaults().synchronize();
print("login success!")
self.dismissViewControllerAnimated(true, completion:nil);
self.performSegueWithIdentifier("nextPage", sender: self);
} else if userEmailStored != userEmail {
// Login unsuccessful (email incorrect)
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
print("login unsuccessful. Incorrect email.")
// Display an alert message
displayMyAlertMessage("Incorrect login details.");
return;
} else if userPasswordStored != userPassword {
// Login unsuccessful (password incorrect)
// Display an alert message
displayMyAlertMessage("Incorrect login details");
//return;
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
print("login unsuccessful. Incorrect password.")
}
The login page comes after an initial 'protected' login/logout screen as ViewController.swift with this code
override func viewDidAppear(animated: Bool)
{
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn");
if(!isUserLoggedIn)
{
self.performSegueWithIdentifier("loginView", sender: self);
}
}
#IBAction func logoutButtonTapped(sender: AnyObject) {
NSUserDefaults.standardUserDefaults().setBool(false,forKey:"isUserLoggedIn");
NSUserDefaults.standardUserDefaults().synchronize();
self.performSegueWithIdentifier("loginView", sender: self);
}
}
I do suggest to have a different approach on this.
If you set a storyboardID to LoginViewController you can directly manage to override the Protected page checking directly in AppDelegate.
For example you can try to do this
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
[...]
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if isUserLoggedIn {
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let vc = storyboard.instantiateViewControllerWithIdentifier("IDYOUSETBEFORE")
window.rootViewController = vc
return
}
I recently managed to release a pod in order to easily handle this situations, have a look at StoryboardEnum lib
I solved this by removing the alert controller function, i.e. the code
displayMyAlertMessage("Login successful. Thank you");
as this was segueing to the 'login successful' popup view controller, instead of the segue that I needed, and in effect blocking the next page, while also not really necessary, as successful login means moving to the next page. I was able to still keep the alert/ popups for 'incorrect login details' which were the only essential alerts.

In swift, how do I only perform a segue after a server has given me a certain response?

In swift, how do I only perform a segue after a server has given me a certain response?
I'd like to click a submit button. That will send a request to the server. Then, if the server responds positively, I want a view to be presented modally, otherwise, I want to write a UIAlertView.
I know how to write the UIAlertView and I have the Modal View prepared, I just can't figure out how to write it such that the modal view only presents itself conditionally.
First you need to give a segue identifier on your storyboard. Then you can use:
self.performSegueWithIdentifier("yourSegueIdentifier", sender: nil)
first make a segue between the view controllers and give the segue identifier
eg: self.performSegueWithIdentifier("SegueIdentifier", sender: nil)
and when you get the response of the service request and on the basis of that check the status or the valid http status code.
eg: if status returns true {
self.performSegueWithIdentifier("SegueIdentifier", sender: nil)
}
or if statuscode == 200...299 {
self.performSegueWithIdentifier("SegueIdentifier", sender: nil)
}
Assuming you have your submit button wired up to an IBAction you could do something like this...
#IBAction func submitClicked(sender: UIButton) {
//try to hit server
let serverResponse = server.trySomeFunction()
if serverResponse {
//server response was successful!
self.performSegueWithIdentifier("SegueIdentifier", sender: self)
} else {
//server response failure, present alert
}
}

Getting NSInternalInconsistencyException in conditional segue in swift

I am performing a conditional segue in UIButton Click event listener. My segue is drawn between "pathanViewController" and "dekhunViewController" in storyboard with "pathanToDekhun" identifier. But i am getting NsInternalInconsistencyException as
*** Assertion failure in -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished], /SourceCache/UIKit_Sim/UIKit-3318.16.14/Keyboard/UIKeyboardTaskQueue.m:374
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the main thread.'
After button click i have performed a external api call and after successful return message, i called the segue with performSegueWithIdentifier. But the segue never happen actually. Below is my code portion in pathanViewController. Please let me know what i am doing wrong.
#IBAction func sendBtnListener(sender: AnyObject) {
if !self.commentSection.text.isEmpty {
var submitVoganti = DataSerialization(brandName: self.brandName!, rating: Int(self.sliderStatus.value*5), commentText: self.commentSection.text, anonymous: switchBox.on ? true : false)
var dataSet = DataSet()
dataSet.postComment(submitVoganti.toJson(),{
(id) in
self.performSegueWithIdentifier("pathanToDekhun", sender: self)
println(id)
})
} else{
println("Comment field should not be empty")
}
}
//Check whether a segue should be triggered or not
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool {
if identifier == "pathanToDekhun" {
return false
}
// by default, transition
return true
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
var dekhunScene = segue.destinationViewController as ThirdViewController
dekhunScene.keyword = self.brandName
}
What i am doing wrong is my performSegueWithIdentifier is not called in main queue. Thats why it throws exception. What i am doing now is just editing my code as below -
dataSet.postComment(submitVoganti.toJson(),{
(id) in
dispatch_async(dispatch_get_main_queue()){
self.performSegueWithIdentifier("pathanToDekhun", sender: self)
}
println(id)
})
and comment out "override func shouldPerformSegueWithIdentifier" function. Thats it.