Back at the start of July I began a contract to develop an iOS app for a Taxi firm. I decided to invest in Xamarin Studio so that I could develop the app in C#. The development took a bit longer than expected due to issues with the server, but it’s now very near completion.
Xamarin, while appearing to have come out of nowhere, is actually a renamed and rebranded version of MonoTouch, so it’s a couple of years old and mature. I use the Visual Studio plugin, which networks a PC to a Mac Mini, allowing me to plug an iPhone into the Mac and debug from Visual Studio. It functions well — there’s an initial 30 second delay to start debugging, but otherwise it runs very fast.
So what have I learned in my six months of Xamarin? Actually, quite a bit. The application I’ve been working on is for taxi drivers to receive jobs and communicate with the office. It replaces a radio and was a conversion of an existing Windows Phone 7 application written in Visual Basic to an iPhone application. Luckily, I was given the source code, though there were still a few gotchas.
This application wasn’t architected as a client server where the server just responds to client messages. Instead, messages could be sent in either direction — from the server when a job was sent out or from the client when logging in.
In iOS, screens are full of Views, which are the controls. These are glued together through ViewControllers, which manage the navigation. Like virtually every other GUI in existence, this runs in the main thread. So I needed to design a main-thread GUI where the user clicks buttons, that is interrupted and redrawn when a TCP message is received.
I decided on a single ViewController that builds up a simple button display. If the user clicks a button, it calls a specified method. Each screen starts by tearing down all the existing controls, then rebuilds the screen. It sounds unusual but is fast and has been trouble free. Each method called is a C# delegate matching the (sender, event) pattern, using the Anaction delegate definition below.
The C# delegate above is used similarly to an iOS delegate, except that iOS uses a class to delegate instead of a method. For instance, when you want to display a UIPickerView, you designate a UIPickerViewDelegate. The delegate class lets you override methods to specify the width, number of items, current selected row and others.
I created a series of UIButton types. One of the quirks of iOS is that you never subclass UIButtons. Instead, you create them using one of several overloaded UIButton class constructors and customize the look. Never try to create your own descendant of a UIButton.
The method I used, below, creates a glass button (using a preloaded glass image) at location x, y with the specified width, height and title. It uses the C# delegate Anaction type to hook up a specified method to respond with a lambda expression when the button is clicked.
To create a button using this method, you’d say something like this:
AddSubview adds a control to a View. Info should be a method that matches the Anaction delegate signature, defined like this:
Classes like UIViewController, UIImage, and UIView are mapped exactly onto the underlying iOS classes. It’s one of the great strengths of Xamarin. The day iOS 6 (and later iOS 7) was launched, they had all the namespaces mapped so they could be used imediately in C#. UIControls like UIButton are subclassed from the iOS NSObject (the root of all objects in the iOS ecosystem) which has the InvokeOnMainThread method, which is also very handy. The statement below lets you run the “enable a NavButton” code in the main GUI thread, even though it’s called from a background thread. That’s the key element to let messages received via TCP interact with the button GUI.
Responding to Background Server Requests
The App talks to a distant server via TCP using a particular packet protocol. To make life harder the server developer hadn’t (a) documented it, (b) given me any source code or (c) told me that the packet structure varied according to the client version it was talking to. I found all that and a bug in the server the hard way. But he and I are still mates and I didn’t lose too much hair.
The .NET TcpClient class proved very much up to the job. However, especially on a 3G environment in a moving vehicle, you must expect that server connections will break. Although TcpClient has a Connected property, it only gives you the state of the last successful read or write. So you only discover that your TCP connection is no longer there and must be reconnected if you try to read it or write to it.
For responsiveness, I used two queues to hold messages: one for receiving and one for transmitting. They were timer driven, with the receive queue checking for data ten times a second. If there was a message to send (in the transmit queue), it sent that first. Here’s the AnyData call below. A server message should be received at least once every six or seven seconds, so if it gets to ten seconds since the last message was received, it assumes the TCP channel has broken and attempts to reconnect.
If the connection has been broken, the zero byte read should give an exception. If it doesn’t and there’s data to be read, stream.DataAvailable gives a true value.
Issues with Xamarin
The Mac version (Xamarin Studio) worked perfectly most of the time. Occasionally the Visual Studio connection had issues and needed VS to be restarted. During the six month period, Xamarin switched to a new system where a Build Server runs on the Mac and is paired with Visual Studio. This has worked consistently except during the initial two weeks, when I couldn’t get it to work at all. The Xamarin support was excellent, though I eventually figured out that my project or solution file had gone corrupt — manually recreating a new one fixed it.
It’s been a steep learning curve and I’ve not reached the top yet, but it’s jelling. There’s a lot less code to write in C# than Objective-C. Once you learn it, it’s much more productive than writing in Objective-C.