I finally found the long lost bug in Archi

I finally traced and fixed a nagging bug in Archi that can lead to orphaned diagram elements or, put another way, a corrupt model file. This was an issue that had occurred for a small number of users for some time, but one I’d never been able to reproduce. Until three days ago.

Analysing an Archi user’s specimen file I discovered that some folders were being stored in XML as <element> tags and not as <folder> tags. This meant that some diagram view objects could not be matched to their corresponding model elements in the model tree. This in turn meant that it was possible to delete the referenced model element thus leading to an orphaned diagram node. It turned out to be a dumb logic bug in the model tree’s drag-drop handler. An edge case, but with serious enough consequences. You can view the bug for yourself in all of its glorious stupidity at Github.

Put simply – if you dragged and dropped a folder onto the same parent folder your file could get screwed.

Fixing this bug has been a cause for major celebration. So much so that, after releasing the new version of Archi, I broke open a bottle of Prosecco and immediately emailed those Archi users who had reported the problem with the good news. Tetelestai!

Now that this bug has finally been squashed and a new build published I hope that all Archi users will download the latest version from the new Archi website.

rip

Parsing JSON in iOS

This is a quick guide to parsing a JSON file in iOS, specifically on the iPhone. I’m not going to go into any detail about the history of JSON or why it’s used in preference to, say, XML. If you want to find out more about JSON then check out the following resources:

http://www.json.org/
http://www.w3schools.com/json/

The use of JSON as a serialisation format has grown in popularity as more and more third parties such as Google, Yahoo, and Twitter provide web services that return JSON formatted data from a given URL appended with a query string. For example, you can get the weather for London from the following URL and appended query (the “q=London,uk” part):

http://api.openweathermap.org/data/2.5/weather?q=London,uk

At the time of writing the returned JSON looks like this:

In order to make some sense of this, the iOS developer needs to parse this information and structure it into model data for their application so it can be usefully displayed. It turns out that from iOS 5 onwards, Apple have implemented a relatively simple framework for reading a JSON stream from a given URL (local or on-line) and parsing that stream into information that can be used in an iOS application.

For the following example I’ve put together a JSON file containing some information about six places of interest. Here’s what the file looks like:

To demonstrate parsing this JSON file, I’ve created a simple iPhone project that reads in the file, parses it and creates a “Location” class for each location entry declared in the JSON. This is then displayed as a list in a table view controller which then links to a detail view controller displaying more information together with a map and a map pin (annotation) showing the location of the selected place.

The example Xcode project is hosted at GitHub and you can either clone it or download it from here:

https://github.com/Phillipus/JSONHandler

(Note that I’ve set up this project to run on iOS 7. You’ll also need to be using Xcode 5.)

Load the project into Xcode and run it in the iOS simulator. When you see the first screen you’ll see a simple table displaying six location names and places:

JSON data in table format

JSON data in table format

Selecting a row in the table view initiates a segue to a new view controller that displays more detail about the location and a pin on a map:

JSON data

JSON data

Let’s examine how we load and display the raw JSON data in the application, starting at the point where the first table is displayed.

Open up the LocationsViewController.m class file and take a look at the viewDidLoad method:

viewDidLoad is the method that’s called when the Table View Controller is first created and displayed, so this is a good place to load the JSON data file. First we create a new instance of the class JSONLoader, which we’ll look at soon, and then a URL which is the location of our JSON file. If the JSON file was located online you would create an online URL here, but for this example we’re using a local file as this ensures we can run the project without any connection issues. Once we’ve done this, we call the locationsFromJSONFile: method on the JSONLoader instance. This will return an NSArray of Location objects that we can then use as a data source to display in the table. Notice that the NSArray instance variable, _locations, has been declared in the first line of the implementation:

Once the array of Location objects has been returned by the call to locationsFromJSONFile:, we then ask the table view to reload its data. This will in turn trigger the call of the Table View Controller methods, tableView:cellForRowAtIndexPath: and tableView:numberOfRowsInSection: which will supply the information needed to display the rows in the table.

Notice that the method call locationsFromJSONFile: is dispatched on a queue. This ensures that the operation to connect to the URL and fetch the JSON data is performed on a background thread so that we don’t block the UI. Once the data has been received we can then load the data in the table on the main UI thread by calling performSelectorOnMainThread:withObject:waitUntilDone:. The golden rule in iOS is that all UIKit objects methods should be accessed on the main thread.

The over-ridden method prepareForSegue:sender: simply ascertains which row in the table was selected and passes on the corresponding Location object to the target destination View Controller. This destination view, LocationDetailViewController, then displays the information in the Location object in a set of text fields and as a pin on a map.

Now that we know how the JSON data is loaded and presented to the user in a table view, let’s look under the hood at the model classes that do the work of parsing the contents of the JSON file and turning it into something that we can use in the application. Open the class file, JSONLoader.m and look at the following code:

The NSURLRequest and NSURLConnection part of the code is pretty much the standard approach to getting data from a given URL. We are using the static method sendSynchronousRequest rather than an asynchronous call because the whole method is being called on a queue as we saw earlier. The magic happens in this line:

The NSJSONSerialization class has a static method, JSONObjectWithData:options:error, which parses an NSData object and returns a Foundation object. This is typically an NSDictionary or an NSArray depending on how the JSON data is structured. The example locations.json file is structured as a dictionary consisting of one key, “locations”, mapped to an array of dictionary values. We access the array with the following line:

We can then iterate through the NSDictionary objects in the array creating one Location class object for each dictionary entry:

We then add this to a NSMutableArray of locations and return it when the method finishes.

Here’s the Location class header file:

And the Location class implementation file:

The Location class is simply a set of properties that map to the key names that are found in the location.json file. If you recall, the first set of data looks like this:

So, by writing code like this:

we are effectively assigning values to the properties in the Location class:

title = “The Pump Room”
place = “Bath”

and so on. (Note that the instance variables are prefixed with underscores. Because the properties are readonly we can only assign values directly to the underlying instance variables which are automatically synthesised for us).

We now have all of the information for a location encapsulated conveniently in a model class, Location.

If we take a look at the LocationDetailViewController.m class file we can see that in the viewDidLoad method we access all of these properties to populate the fields in the view. Note that the boolean value for “visited” is a NSNumber type which has to be converted to a BOOL type in order to set the value for the UISwitch control. The latitude and longitude properties are also NSNumber objects and these have to be converted to double values to create the coordinates for the map pin.

Wrap up

This post has, I hope, given you a start with parsing JSON and mapping the data to a simple model class. Of course, the structure and hierarchy of your own model classes will depend on the structure of the data in whatever JSON file or stream that you are working with.