iPhone/iPad Development With MonoTouch – A Tutorial

by on October 30, 2012 10:52 am

What if your boss came to you today and said: “We need to build a mobile iPhone/iPad application for our company’s legacy desktop application.”

After the excitement of finally working on a mobile application subsides, you might begin to wonder if you’ve actually just gotten yourself down a rabbit hole. 

As a .NET development shop, you realize that you don’t have Objective-C programming skills. Plus the requirements of the mobile application must have the same business rules as the desktop version. Since the user would like the application as soon as possible, you don’t have the time to learn and rewrite the current desktop application into Objective-C.

Don’t panic, MonoTouch by Xamarin is here to help you.

Overview

MonoTouch allows you to reuse your C# skills to build iPhone and iPad applications. Unlike HTML5 options, MonoTouch is natively compiled to the iOS platform. This native compile allows you full access of Apple’s API and UI. Some of MonoTouch’s key features include:

  • MonoDevelop – Just like Visual Studio, MonoDevelop is an IDE that provides code assist, project management, and debugging tools.
  • C# – The features of the language Type-Safety, Dynamic Constructs, Functional Constructs such as Lambdas, LINQ, Automatic Garbage Collection are all available.
  • Inter-operability – Third party libraries that are written in Objective-C or C/C++ can be called directly from MonoTouch.
  • Re-usability – The common background business logic can be reused in Windows 7 & 8 mobile, and Mono for Android mobile applications.

Prerequisites

In order for you to use MonoTouch, an Apple computer running Snow Leopard (or later) is required. Since the application is compiled natively, Apple’s Xcode SDK is required. The Xcode development enviroment also provides the iOS emulator for testing the application. If your manager doesn’t want to spend the entire IT budget on your new Apple Macbook, a cheap alternative is the Mac Mini.

MonoTouch is free to download, but it is limited to only running the application within the iOS emulator. If you want to install applications on a iPhone or iPad, then you will need to buy a license.

Download and install the following: 

  • Apple’s Xcode from either the Mac App Store or Apple’s iOS developer website
  • MonoTouch from Xamarin

First Application

Instead of doing a “Hello World” application for the millionth time, we’ll work on an example application that will retrieve the current weather conditions based on location.

A working example can be downloaded from the Keyhole’s GitHub repository: https://github.com/in-the-keyhole/khs-blog-examples.git

After clicking the MonoDevelop IDE icon, lets begin with starting a new MonoTouch project:

After clicking the OK button, a single view template project has been created for you. As a Visual Studio developer, the MonoDevelop environment should look like an old friend. Solutions, projects, files and references are laid out the same way as Visual Studio.

Let’s take a close look at the template that MonoTouch created for you:

  • Main.cs – This file is the starting point of the application.
  • AppDelegate.cs – This file contains the main application class that is responsible for listening to events.
  • CurrentTemperatureViewController.cs – This is where you will write the code to interact with the screen.
  • CurrentTemperatureViewController.designer.cs – This class is automatically updated when you add controls to the screen from XCode IDE.
  • CurrentTemperatureViewController.xib – This file is the screen design as describe by XML.
  • Info.plist – This file contains properties for the application such as application name and target platform

Building the Screen Layout

Double click the CurrentTemperatureViewController.xib file within the project. This will open Xcode and visually display the screen layout. Using the Xcode editor, you can lay out the controls by dragging them from the object list to the screen.

In our example, we are going to add four labels and a button. To learn more about how to use Xcode, visit Apple’s Developer site.

From the object pane of Xcode, drag and drop the UILabels and UIButton to the screen area.

Wire Controls

Apple provides Outlets and Actions that implements the interaction needed for our two controls.

  • Outlets – Outlets work exactly the same as properties in .NET applications.
  • Actions – Actions work in the same manner as the command pattern does for .NET. Actions allow the developer to wire many controls to the same method.

To add an Outlet or Action: change the Xcode view mode to Assistant Editor, which will split the editor screen. While holding the CTRL key, drag the controls from the view to any space in the code after the @interface definition. A popup will be displayed asking for the type and name. Select Outlet and give it a name. Also for the button, we will create an Action for the Touch Up Inside event.

For more detail instructions on adding Outlets and Actions, I recommend visiting Xamarin’s Hello World example.

Now that controls have been wired up to the screen, we now need to start coding the business logic for the windows.

Reusing Business Logic

One of the advantages of using Monotouch is that the business logic that you already wrote for those legacy applications can be reused.  This also includes most 3rd party libraries that are written for .NET.  The domains, validations, and services can be used in the Monotouch application.

In this example, I will create two simple domains Location and Weather.  Even though I’m creating the code within the Monotouch project, for better reusability the code should be in its own library.  This way it can be shared by both the legacy application and Monotouch.

public class Location
{
	public string City { get; set; }
	public string State { get; set; }
	public string Zipcode { get; set; }

}

and

public class Weather
{
   public string Temperature { get; set; }
   public string Condition { get; set; }
   public string Humidity { get; set; }
   public string Wind { get; set; }
}

Now that the domains have been created, I will create a simple service that will call the Yahoo Weather API.  Our service will pass the zip code to the Yahoo Weather API and then parse the current conditions from the xml response.

public class YahooWeatherService : IWeatherService
{
   private const string URL_YAHOO_WEATHER = "http://weather.yahooapis.com/forecastrss?p={0}";
   private readonly string[] DIRECTIONS = {"N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW", "NW","NNW"} ;
   public Weather CurrentWeather (string zipcode)
   {
      string url = string.Format(URL_YAHOO_WEATHER, zipcode);
      return ProcessService(url);
   }
   private Weather ProcessService (string url)
   {
      Weather weather = null;
      XmlDocument doc = new XmlDocument ();
      // Load data
      doc.Load (url);
      // Set up namespace manager for XPath
      XmlNamespaceManager ns = new XmlNamespaceManager (doc.NameTable);
      ns.AddNamespace ("yweather", "http://xml.weather.yahoo.com/ns/rss/1.0");
      // Get current forecast with XPath
      XmlNode condNode = doc.SelectSingleNode ("/rss/channel/item/yweather:condition", ns);
      XmlNode astrNode = doc.SelectSingleNode ("/rss/channel/yweather:atmosphere", ns);
      weather = new Weather {
         Condition = condNode.Attributes["text"].Value,
         Temperature = condNode.Attributes ["temp"].Value,
         Wind = getWindDescription(doc, ns),
         Humidity = astrNode.Attributes["humidity"].Value
      };
      return weather;
   }
   private string getWindDescription (XmlDocument doc, XmlNamespaceManager ns)
   {
      XmlNode windNode = doc.SelectSingleNode ("/rss/channel/yweather:wind", ns);
      var speed = windNode.Attributes["speed"].Value;
      var degreeString = windNode.Attributes["direction"].Value;
      float degree = 0;
      float.TryParse(degreeString, out degree);
      int index = (int) ((degree / 22.5) + 0.5);
      index = index % 16;
      string name = DIRECTIONS[index];
      return string.Format("Wind: {0} at {1}mph", name, speed);
   }
}

Location and Geocode

Now that the business and service logic are done, we need to retrieve the GPS coordinates and the location.  The nice thing about using Monotouch is that the classes are named the same as Apple’s own classes.

First, let’s create a delegate class that will be used by the GPS. This class will be extended from the CLLocationManagerDelegate class. The one method that will be overridden is the UpdateLocation. When the GPS updates the coordinates, the UpdateLocation method is called with the new values. The CLGeocoder class method ReverseGeocodeLocation will take the coordinates from the GPS and return the address information to the handler:

public class LocationDelegate : CLLocationManagerDelegate
{
    private CLGeocoder geocoder = null;
    private IWeatherService WeatherService {
        get { return new YahooWeatherService (); }
    }

    private CurrentTemperatureViewController screen;
    public LocationDelegate (CurrentTemperatureViewController screen) : base()
    {
        this.screen = screen;
    }

    public override void UpdatedLocation (CLLocationManager manager, CLLocation newLocation, CLLocation oldLocation)
    {
        if (screen.CurrentWeather == null)
        {
            geocoder = new CLGeocoder ();
            geocoder.ReverseGeocodeLocation (newLocation, ReverseGeocodeLocationHandle);
            manager.StopUpdatingHeading();
            manager.StopUpdatingLocation();
        }
    }

    public void ReverseGeocodeLocationHandle (CLPlacemark[] placemarks, NSError error)
    {
        Location loc = new Location();
        for (int i = 0; i < placemarks.Length; i++) {
            loc.Zipcode = placemarks [i].PostalCode;
            loc.City = placemarks[i].Locality;
            loc.State = placemarks[i].AdministrativeArea;
        }

        if (screen.CurrentWeather == null)
        {
            screen.CurrentWeather = WeatherService.CurrentWeather(loc.Zipcode);
            screen.CurrentLocation = loc;
            screen.DisplayScreen();
        }

    }
}

Controller and AppDelegate

We are now on the home stretch for running the application. The last thing we need to do is set up the controller class.

The CurrentTemperatureViewController class was created by the MonoTouch template wizard. The ViewDidLoad method is called when the view is about to load, and before the constructor is called. In this method, we are going to initialize the CLLocationManager and start the GPS location updates. The DisplayScreen is called from the LocationDelegate that we created earlier. The method will copy the values to the controls that we created on the screen layout. The Refresh method is called during the click event of the refresh button.

public partial class CurrentTemperatureViewController : UIViewController
{
   // Initialize a location manager
   private CLLocationManager iPhoneLocationManager = null;
   private Weather CurrentWeather { get; set; }
   private Location CurrentLocation { get; set; }
   public CurrentTemperatureViewController () : base ("CurrentTemperatureViewController", null)
   {
}
   public override void ViewDidLoad ()
   {
      base.ViewDidLoad ();
      // Perform any additional setup after loading the view, typically from a nib.
      iPhoneLocationManager = new CLLocationManager();
      iPhoneLocationManager.Delegate = new LocationDelegate(this);
      iPhoneLocationManager.StartUpdatingLocation();
      iPhoneLocationManager.StartUpdatingHeading();
      }
   public void DisplayScreen ()
   {
      lblTemp.Text = CurrentWeather.Temperature + "ツー F";
      lblCondition.Text = CurrentWeather.Condition;
      lblWind.Text = CurrentWeather.Wind;
      lblCityState.Text = string.Format("{0}, {1}", CurrentLocation.City, CurrentLocation.State);
   }
   public override void ViewDidUnload ()
   {
      base.ViewDidUnload ();
      // Clear any references to subviews of the main view in order to
      // allow the Garbage Collector to collect them sooner.
      //
      // e.g. myOutlet.Dispose (); myOutlet = null;
      ReleaseDesignerOutlets ();
   }
   public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
   {
      // Return true for supported orientations
      return (toInterfaceOrientation != UIInterfaceOrientation.PortraitUpsideDown);
   }
   partial void Refresh(NSObject sender)
   {
      CurrentWeather = null;
      lblTemp.Text = "";
      lblCondition.Text = "";
      lblWind.Text = "";
      lblCityState.Text = "";
      iPhoneLocationManager.StartUpdatingLocation();
      iPhoneLocationManager.StartUpdatingHeading();
   }
}

The last thing to do is set up the singleton AppDelegate class. This class will initialize the application during startup and setup any notifications. The main method to be implemented is the FinishedLaunching method, which will define the root controller. One caveat of the FinishedLaunching method is that code has to complete within 15 seconds or the application will shutdown. If you need a long running service to retrieve data, create a new thread for the task.

[Register (&quot;AppDelegate&quot;)]
public partial class AppDelegate : UIApplicationDelegate
{
   // class-level declarations
   UIWindow window;
   public override bool FinishedLaunching (UIApplication app, NSDictionary options)
   {
       window = new UIWindow (UIScreen.MainScreen.Bounds);
       window.RootViewController = new CurrentTemperatureViewController ();;
       window.MakeKeyAndVisible ();
       return true;
   }
}

Now that this is complete, we can run the application and see something like the following:

Final Thoughts

As you can see this is a simple application, but it gets you an idea of what Monotouch can bring to the table.  So when the boss asks about exposing that legacy application to mobile platforms, you can be confident about implementing the application.

In a later blog post, I will discuss in more detail navigation and the use of third party libraries. In the meantime, go to the Xamarin website and review the examples. It has a plethora of information from code snippets to guides. Good luck!

– Mark Fricke, asktheteam@keyholesoftware.com

  • Share:

4 Responses to “iPhone/iPad Development With MonoTouch – A Tutorial”

  1. David says:

    Very helpful, thanks… David

  2. iPhone/iPad Development With MonoTouch – A Tutorial…

    Thank you for submitting this entry – Trackback from MonoTouch.Info…

  3. [...] iPhone/iPad Development With MonoTouch – A Tutorial [...]

  4. [...] my previous article, I gave a tutorial on how we can use Xamarin.iOS (formally known as Monotouch) to build iOS mobile [...]

Leave a Reply

Things Twitter is Talking About
  • Have a happy & safe holiday weekend!
    August 29, 2014 at 3:55 PM
  • Useful #JAXB primer that illustrates the power from tools & frameworks that unobtrusively interact with POJOs - http://t.co/J1s5DpcsCp
    August 29, 2014 at 3:19 PM
  • The Keyhole team fantasy football league begins! Huge thanks to our commissioner @zachagardner. Good luck to all in the virtual gridiron!
    August 28, 2014 at 5:30 PM
  • Shout out to last year's winner of our Keyhole #fantasyfootball league - Adi Rosenblum (@adidas28). Will his reign continue? :-)
    August 28, 2014 at 5:30 PM
  • @dashaun That is the perfect way to put it - we are very excited! Great to meet you officially.
    August 28, 2014 at 4:53 PM
  • Check out a quick intro to Functional Reactive Programing and #JavaScript - http://t.co/4LSt6aPJvG #FRP http://t.co/m6G1Kqbwyi
    August 28, 2014 at 4:06 PM
  • When you pair #JAXB & #JPA, you can expect some "gotchas." Here are techniques to help you overcome the hurdles - http://t.co/J1s5DpcsCp
    August 27, 2014 at 1:56 PM
  • Interesting perspective - Famo.us talks big, but jQuery Foundation isn't worried: http://t.co/o9lLpPoh2G Thoughts?
    August 27, 2014 at 12:41 PM
  • We are delighted to say that RJ (@RJvXP) & Donna (@dkbdevlab) join Keyhole today. Welcome to the team!
    August 27, 2014 at 9:22 AM
  • RT @codeproject: Learning MVC - Part 5 Repository Pattern in MVC3 Application with Entity Framework by Akhil Mittal http://t.co/z603gpAH…
    August 27, 2014 at 9:15 AM
  • Know a bright new grad looking to learn? We're seeking a team member on our business side of the Keyhole house - http://t.co/GDvFVmoMF9
    August 26, 2014 at 3:29 PM
  • When you pair #JAXB & #JPA, you can expect to encounter some "gotchas." Techniques & learning to overcome hurdles - http://t.co/J1s5DpcsCp
    August 26, 2014 at 11:12 AM
  • Don't miss Mark Adelsberger's newest post on the Keyhole blog: #JAXB – A Newcomer’s Perspective, Part 2 http://t.co/J1s5DpcsCp
    August 25, 2014 at 1:21 PM
  • A huge welcome to Mike Schlatter who joins the KHS team today!
    August 25, 2014 at 12:33 PM
  • Never used JAXB? Check out a simple usage pattern that pairs #JAXB’s data binding capabilities with JPA - http://t.co/Ki9G04pLR6
    August 22, 2014 at 8:35 AM
  • Check out a quick intro to Functional Reactive Programing and #JavaScript - http://t.co/YGSsz5eynl #FRP http://t.co/m6G1Kqbwyi
    August 21, 2014 at 11:32 AM
  • Our team is riding #BikeMS to support the fight against Multiple Sclerosis. Get involved - http://t.co/GGObSd073P http://t.co/vZpWRXkQ3z
    August 21, 2014 at 9:09 AM
  • @dtkachev Thanks for the tweet! The server is back up now - sorry for the inconvenience. Have a good day!
    August 21, 2014 at 9:03 AM
  • RT @m_evans10: @joewalnes A SQL query goes into a bar, walks up to two tables and asks, "Can I join you?"
    August 20, 2014 at 3:55 PM
  • Have you read @wdpitt's newest book? - Web Essentials using #JavaScript & #HTML5. Free PDF download via @InfoQ: http://t.co/lesuPJ770I
    August 20, 2014 at 2:31 PM
Keyhole Software
8900 State Line Road, Suite 455
Leawood, KS 66206
ph: 877-521-7769
© 2014 Keyhole Software, LLC. All rights reserved.