UIBarButtonItem's don't appear after Fingerprint Authentication - ios

I am creating an app, and to access the main screen of the app the user has to input there fingerprint. I have it setup so that when the fingerprint is correct it programmatically performs a segue to a navigation controller which is connected to the main view controller. Here is my code:
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Authenticate with Touch ID"
context.evaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, localizedReason: reason, reply:
{(succes: Bool, error: NSError!) in
if succes {
self.showOrHide(true)
ProgressHUD.showSuccess("Success")
self.performSegueWithIdentifier("passwordCorrectSegue", sender: nil)
} else {
}
})
} else {
self.touchIDLabel.hidden = true
self.touchIDImage.hidden = true
}
The problem is when I perform the segue and it goes to the navigation controller which shows the view controller, the UIBarButtonItem's do not show on the top left and top right of the screen. You can still click on the top left and top right of the screen and the actions for those buttons would run. The problem is that the UIBarButtonItem's are just not showing. Another thing I have tried is that you also have the option to enter in a password, and when the password is correct it goes to the next view controller... and it works perfectly. Does anyone know how to fix this?
The UIBarButtonItems just don't show when I use the method
self.performSegueWithIdentifier("passwordCorrectSegue", sender: nil)
when trying to perform that method using the fingerprint method.

I had the exact same issue: I have 2 VC, each being able to segue to a third one ; if I segue from the first, the right bar button item is not visible (but still works), but if I segue from the second one, the right bar button item is visible.
I guess it's a bug in iOS9.
The workaround I used was to force the initialization of the right bar button item in the destination view controller "viewDidLoad":
override func viewDidLoad() {
super.viewDidLoad()
// Force right bar button item when using performSeguewithIdentifier (bug in iOS9?)
navigationItem.rightBarButtonItem = UIBarButtonItem(
image: UIImage(assetIdentifier: .Profile),
style: UIBarButtonItemStyle.Plain,
target: self,
action: Selector("displayUser"))
}
That fixed the issue for me (at least until Apple fixes this bug).

Related

Why UIButton is unresponsive?

I have a UIButton on top of every other views, pushing the next screen, but it's unresponsive to tapping.
Debugging, I have noticed that the User Interaction is ON but also OFF. I mean:
When I select the button at the view hierarchy) it says is ON.
When I select the button directly at the storyboard, it says is OFF.
Take a look at the image above.
Also, the outlets are connected and the call is correct:
code
#IBAction public func onFrontPressed(_ sender: UIButton) {
let destination = OnboardingAViewController(nibName: "OnboardingAViewController", bundle: nil)
self.navigationController?.pushViewController(destination, animated: true)
}
Does anyone knows what's going on here?
Solved!
There was 1 fully transparent gradient view above the button.
When I deleted it, everything was working again.
Thanks, community!

How to add a tabbar after a user action

I have an app that doesn't have to show any tab when the user isn't logged in. I'm facing many issues with this functionality. First of all, I had embed the views, after the login screen, into a tab bar controller and everything was showing ok, except when I had implemented the login feature. As it's an async call, I had to wait until the credentials were validated. I wasn't able to do this in the shouldPerformSegue method or any other method provided by apple because you can't block the main thread until the async stuff is done, so the segue has to be done programaticaly in an IbAction:
#IBAction func doLogin(sender: AnyObject) {
userIsLogged = false
let apiCall = webApi()
apiCall.callCheckIsUserLogged(nil, password : self.passwordField.text, email: self.mailField.text){ (ok) in
if ok {
if(userIsLogged == true){
dispatch_async(dispatch_get_main_queue()) {
self.performSegueWithIdentifier("loginUser", sender: self)
}
}else {
NSOperationQueue.mainQueue().addOperationWithBlock{
print("User not logged in")
self.alert.message = "Please enter valid credentials"
self.displayAlert()
}
}
}
}
}
But this has driven me to another issue: after the programatic segue, my tab bar controller was disappearing, and after read a while it looks like the only way to avoid this is to embed your tab bar controller into a navigation controller. So I did it, but now, I got many new issues. First of all I got two navigation controllers, the one who is at the very beginning of the project and this new one I have embed into the tab bar controller. A picture will illustrate this better than my words:
Now I have two navigation controllers, and I don't know how to hide the top one. Already tried:
self.navigationController?.navigationItem.hidesBackButton = true
But is hiding the arrow and I need to hide the other one navigation controller. But the best thing indeed would be to see the best approach for this kind of cases, when you want to add a tabBar controller embed into a navigation controller in the middle of the project.
Thanks all
I guess you can take another approach. Make login storyline and your app storyline distinct.
Have a storyboard for your login procedure, and another storyboard for your home (or whatever you like) and manage them in AppDelegate.
This is how i did it:
if /* user must log in */ {
self.window?.rootViewController = loginStoryboard?.instantiateInitialViewController()
self.window?.makeKeyAndVisible()
}
else {
self.window?.rootViewController = homeStoryboard?instantiateInitialViewController()
self.window?.makeKeyAndVisible()
}
Put this code in a method (for example called manageRootViewController()) and call it at app launch, or after your login. (You can also add custom animations if you like)

Overwrite ios back button

I have an app that displays a webView of a web page. The web consists of a main page with a lot of subpages. When I am on the main page I want the navigation Back button to to keep the default behaviour of going back to the previous view controller. But when the web is on a subpage I would like the navigation Back button to take the web to the main web page.
So I need to catch when the user presses the back button and if he is on a web subpage take him to the web main page and prevent the webView from closing. I was thinking that I can catch the back button using viewWillDisappear(), but how can I prevent the view from closing?
Similar to KickimusButticus' answer:
If you want to more easily do it using the storyboard and such, you could hook up your back button to an IBAction like so:
#IBAction func back() {
}
And have internal testing for whether or not the user is in a sub-page of the webview. If they are, you can mess with the webview. If they are on the home page, you could simply use the back button to segue to your main view controller or use the self.dismissViewControllerAnimated(true, completion: nil) to dismiss that view controller.
Check this post out:
Execute action when back bar button of UINavigationController is pressed
Something like this ought to do, in your view controller code:
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true
let customBackButtonItem = UIBarButtonItem(title: "Back", style: .Bordered, target: self, action:#selector(customBackMethod(_:)))
self.navigationItem.leftBarButtonItem = customBackButtonItem
}
// #objc is so we can use #selector() up above
#objc func customBackMethod(sender: UIBarButtonItem) {
if webView.canGoBack {
webView.goBack()
}
}
Note that you may have to use UIBarButtonItem(image:, style:, target:, action:) if you want a 'back' image, or UIBarButtonItem(customView:). See this question and answer for more details: https://stackoverflow.com/a/36180934/892990

Missing Navigation's or Back Button's Title When Push ViewControllers in Succession

I have a problem on UINavigationController when pushing view controllers in succession.
For information, I use XCode 7.0, build targeting iOS 8, and the app running on Simulator 9.0.
Here's the view when user manually tap the tableview's cell:
As shown on the above screenshots, the navigation's and back button's title were rendered normally.
But when I did this programmatically, like this (stack is array of UIViewController):
for controller in stack {
self.mainNavController.pushViewController(controller, animated: false)
}
or using delay on 0.0 second like this:
for controller in stack {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64((0.0 * Float(NSEC_PER_SEC)))), dispatch_get_main_queue(), {
self.mainNavController.pushViewController(controller, animated: false)
})
}
It will show the final result like this (left is w/o delay, right is w/ delay):
Notice the missing navigation title on the left screenshot (w/o delay) and missing back button title on the right screenshot (w/ delay).
This issue has confuse me for days. Any idea of why this is happening? Does anyone know how to fix this? Or at least, work around this issue?
Thanks in advance.
This is what I have done in the past. You might find it helpful:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let myBackButton = UIBarButtonItem()
myBackButton.title = "This is my back button"
navigationItem.backBarButtonItem = myBackButton
}
This is happening because the intermediate view controllers are not being told to load so it isn't able to load things properly like the correct messaging for the back button. For any intermediate viewControllers, call loadViewIfNeeded() and then the upper view controllers can get all the required info from them.

Unwind segue from navigation back button in Swift

I have a settings screen, in that I have a table cell. By clicking on that I take to another screen where user can choose an option and I want it back in the previous view controller when back button is pressed.
I can put a custom bar button item, but I want to return to the parent view controller using the back button in the navigation bar rather than with a custom button on the view.
I don't seem to be able to override the navigation back button to point it down to my unwind segue action and since the back button doesn't appear on the storyboard, I cant drag the green Exit button to it
Is it possible to unwind a push segue with the back button?
Here's my solution, based on Objective-C code from Blankarsch to this StackOverflow question: How to trap the back button event
Put this code inside the View Controller you want to trap the Back button call from:
override func didMoveToParentViewController(parent: UIViewController?) {
if (!(parent?.isEqual(self.parentViewController) ?? false)) {
println("Back Button Pressed!")
}
}
Inside of the if block, handle whatever you need to pass back. You'll also need to have a reference back to calling view controller as at this point most likely both parent and self.parentViewController are nil, so you can't navigate the View Controller tree.
Also, you might be able to get away with simply checking parent for nil as I haven't found a case where pressing the back button didn't result in parent being nil. So something like this is a bit more concise:
override func didMoveToParentViewController(parent: UIViewController?) {
if (parent == nil) {
println("Back Button Pressed!")
}
}
But I can't guarantee that will work every time.
Do the following in the view controller that has the back button
Swift 3
override func didMove(toParentViewController parent: UIViewController?) {
if !(parent?.isEqual(self.parent) ?? false) {
print("Parent view loaded")
}
super.didMove(toParentViewController: parent)
}
I tried the same and it seems that you cannot catch the standard back button's action so the solution will be to use a custom button and bind it to a segue which leads back to the previous page.
You could use some sort of delegation as you did or use a custom back button and an unwind segue.
Better even, you could handle passing data between your view controllers using a mediator:
http://cocoapatterns.com/passing-data-between-view-controllers/

Resources