Mistakes Were Made: iOS App in Xamarin
This post is an artifact from my recent participation in an experiment in “learning as a project” (I made that up). I went through the process of adding TouchID to an app in a platform I have never used before (Xamarin).
I’ve constructed a list of all the mistakes that I made as I wandered through the world of developing for iOS. I hope the list will help someone out there. Alternatively, use these mistakes to make fun of me.
1. When the Tunnel has no Light
The first problem I encountered occurred during the set-up of my environment (naturally). Using the automated installer for Xamarin Studio on my Windows machine, the logs contained this exception: Failed to compose local base path from ‘Z:” ‘ and ‘Xamarin\MonoForAndroid’. Will use the default location (<USER_HOME>)??
I take it that this happened because of the way my environment was set-up. I couldn’t figure out how to point it somewhere else. After spending a day working to fix this, I did a manual installation. For reasons unknown, I still couldn’t get the Xamarin build host for my iOS app working, so I switched over to using Xamarin Studio on a Mac machine (which installed automatically to perfection and can build for itself).
Xamarin provides an explanation of how to set-up the build host here. If the installer fails, you can try following the manual instructions on the pop-up.
2. Correctly Transition using a “Logout” Button
At one point, I needed a log-out function for the app to perform manual tests. My initial idea was to just create a segue, because I learned that they were used for transitioning between views. Apparently, there’s a little more to it than that.
The two resources that I ended up using to figure out how to do the transition can be found here and here. More specifically, I used the PopToViewController(UIViewController, Boolean) method that is found in the “Public Methods” heading of the second link.
By keeping a reference to my “SplashViewController”, I could use the PopToViewController method to remove the view frames on the stack. This avoided the problem of layering views on top of one another repeatedly.
3. LAError message vs. LAStatus message
Early in the process of adding TouchID, I wanted to check the kind of error returned by the LocalAuthentication framework. The iOS version of this error is LAError. The version provided by Xamarin is slightly different, called LAStatus.
The “error” state of the LAContextReplyHandler provided by Xamarin is an object of type NSErrorException. By converting and casting the NSErrorException.Code to an LAStatus, you can access the enumeration to check against the converted LAStatus. This forum post briefly describes the LAStatus vs. LAError (and lists the different codes and their mapping). This blog describes a method for converting the NSErrorException.Code into a LAStatus.
4. Application Flow is Pretty Important
What made sense to me: The user has opened my app, and my app has the ability to use TouchID. I had better ask them if they want to use TouchID as fast as possible so I don’t fall behind!
What actually makes sense: I should let the user log-in first. The user probably doesn’t care that they can use TouchID before they’ve decided if they want to log-in or not.
I’ve embedded an image of the correct flow below.
5. UIAlertViews Don’t Wait For Input
As it turns out, UIAlertViews do not wait for you to click on them before the code continues executing. The LocalAuthentication logic will wait for input. I ended up with a situation where the prompt to use or not was overtaken by the prompt for TouchID.
The solution I chose ended up being to separate out the choice into its own view. The app flow becomes blocked until the user makes a selection on whether or not to bind TouchID. I also switched to using yes/no buttons in a separate View directly.
6. Views and ViewControllers are Different
I found myself confused by what I had selected when clicking on Views/ViewControllers on the storyboard. The ViewController is the part that I was targeting. I needed to override it with our BaseController class. After creating and deleting the view multiple times, I had half a dozen copies in my workspace with different names. It took me awhile to understand that deleting the ViewController on the storyboard was not removing it from the project.
The other mistake here made me feel quite silly. I became confused by the difference in clicking on a View vs. a ViewController. The ViewController is the very outside of the storyboard element (which makes sense in hindsight). The ViewController is accessible by clicking one of the below locations.
7. Segues Bound to a Button
While working on re-structuring the application flow, I encountered a strange situation. When I would click my “Login” button, which should have prompted about TouchID, the application immediately went into the “Logged-in” state. That’s strange.
After playing around in the Storyboard file for a while, I found the culprit. The segue was originally dragged from the button directly to the new view. Apparently, that matters, and is a way to keep from having to make the transition in code. Make sure to click on segues and see if they are bound to the ViewController or some other control.