Tag Archives: development

Swift Hate

I’m seeing a surprising amount of vitriol aimed at Swift, Apple’s new programming language for iOS and Mac development. I understand that there can be reasoned debate around the features (or lack thereof), syntax and even the necessity of it but there can be little doubt about the outcome: if you want to consider yourself an iOS developer, it’s a language that you will need to learn.

The only variable I can think of is when you learn it.

I think it’s perfectly reasonable to delay learning it as you have code to deliver now and because Swift is, well, very beta currently.

But asking what the point of Swift is not constructive. Asking what problems can be solved exclusively by Swift makes no sense at all you can do almost anything in most programming languages. Just because Intercal is Turing complete doesn’t mean that you’d want to use it for any real work. What varies between languages is what’s easy and what’s hard.

Objective-C undoubtedly makes some things easier than Swift. It’s a more dynamic language and its C foundations open up a lot of low-level optimisations that probably are not there in higher level languages.

But that same flexibility comes with a price: segmentation faults and memory leaks; pointers; easy-to-get-wrong switch statement; a lack of bounds checking. It also inherits a lot of ambiguity from original C language specification which makes certain automatic optimisations impossible.

How many applications require low-level optimisations more than safety? (And that’s ignoring that the biggest optimisations are usually found in designing a better algorithm or architecture.) How often is it better to have five lines of code instead of one? Every line is a liability, something that can go wrong, something that needs to be understood, tested and maintained.

Whatever its failings, it’s already clear that Swift is more concise and safer than Objective C.

There are absolutely applications where Objective C, C or C++ would be a better choice than Swift. It’s the old 80-20 rule applied to a programming language. And, for those resistant to learning a new language, the 80% is not on “your” side.

Right now, some of this requires a bit of a leap of faith. Swift clearly isn’t finished. You can either learn it now and potentially have some say on what the “final” version looks like, or you can learn it afterwards and just have to accept what’s there. But, either way, you’ll probably using it next year. Get used to it.

What you forgot from your Computer Science Degree

Last night I did a short presentation about my WSLHTMLEntities open source project at the London iOS Developer Group meeting. You can see the slides here:

Since last time I did a talk there people snickered because I built the slides using PowerPoint, this time I decided to use the latest Apple technology: Keynote in iCloud. Unfortunately this was a bit too new for the Mac Pro they use in the Apple Store, so we ended up downloading a copy in PowerPoint format and loading that into the local copy of Keynote. Nothing is ever simple.

One question I got at the end that I was unable to answer is how well it performs compared to other solutions.

This afternoon I ran a few quick tests.

Firstly I added two further methods of performing the HTML entity replacement:

  • Google Cocoa Toolbox
  • Use the new iOS 7 NSAttributedString feature where it can load a HTML document

The last option, while built-in and easy to implement, is not something you’d want to consider if you had any performance requirements. First, it has to run on the main thread. Second, it’s memory footprint is way higher than either of the other two solutions. And, finally, it’s slow. In my tests I did a loop of 10,000 iterations. Because of the memory problem I only ran 1000 iterations of the NSAttributedString solution, but it was still about 15 times slower than my version when doing the full 10,000 records (i.e., over 150 times slower overall).

So I’ve not included it in the charts below.

HTMLEntityChart

I ran eight simple tests with each of the parsers.

There is no clear winner.

As I speculated, WSLHTMLEntities is much more consistent than the other two. Google’s varies a lot depending on where in the mapping list the “solution” lies. Replacing ◊ (near the end of the list) takes 50% longer than & (near the beginning) for example.

Still, you’d have to be pretty obsessive to pick one of these solutions for performance reasons alone. Interesting to find out, though!

CameraGPS debrief

As happy as I am with the way that my new app, CameraGPS, a GPS logger application for people who want to geotag their photographs, came out I can’t say that it’s exactly as I envisioned it at the start of the process.

The idea was something like this: many of the GPS logger apps in the App Store require you to either use iTunes file sharing (who connects their iPhone’s to iTunes any more?) or mail yourself the exported document or sign up to some third party fitness or trekking website. Mailing yourself stuff just didn’t feel very slick and I didn’t want to record my trails for fitness purposes.

I felt that there must be a better way. The better way, I thought, was to use iCloud to share the files between iOS and a Mac. This would require writing a recorder app for iPhone and an “exporter” app for the Mac.

It didn’t work out that way in the end. Here’s why.

You see all kinds of horror stories from people who have had to deal with iCloud. Most of those stories come from people who used the Core Data syncing, while there are a few apps that successfully use the document syncing model, not least some of Apple’s own. Using the document storage I figured that, worst case, if something gets screwed up it would only affect a single trail. Using Core Data syncing, an error could mean corrupting the whole database.

So this became the plan: record each GPS trail into a separate document. Because I wanted to “random access” parts of each trail and because I didn’t want to have to load the whole trail into memory all the time, I decided to use Core Data to manage the document. On iOS this is called UIManagedDocument.

The first and most obvious fail here is with UIManagedDocument’s cross platform capabilities. Or rather the lack of them. Unless you count iPhone to iPad as cross platform it just doesn’t work. There is a class on the Mac called NSPersistentDocument that is also a Core Data store and looks on the surface to do exactly the same thing… but it’s in a different format. On iOS it’s a “package” which includes a Core Data store. On the Mac it’s just the store. Mike Abdullah has written an open source component that attempts to be bridge the gap but — as we’ll see shorty — I didn’t get to the point where I was able to test it in anger.

But let’s take a step backwards. Let’s assume that all we need is to move data between iPhone and iPad. Then what?

Well, technically it works — in the sense that documents transfer between machines — just not in a way that would make sense to ship.

To make sense of why it doesn’t work let’s take a quick diversion to look at the format of a UIManagedDocument. As hinted above, it’s not a file. Rather it’s a “package” which a number of files within.

An important file is called DocumentMetadata.plist. This tells you about the rest of the package and is created when the document is. There’s little in here that needs to be changed after document creation. The interesting stuff is all stored in a SQLite file, which is stored in a folder.

When files are stored in iCloud you can’t just use NSFileManager to poke around and see what’s there. Instead you create a query using NSMetadataQuery — which supports both a predicate and a sort descriptor — and listen for updates. Updates come in two parts, the initial state and then changes to that state.

After a few false starts I ended up using KVO to populate a table view showing the current list of documents. This worked nicely, showing the full list, updating automatically when changes arrived over the network.

But, and it’s a big but, what if you want to sort the list. Pretty basic requirement, no?

One of the fun things about NSMetadataQuery is that it can only look for files. Folders are “invisible.”

Most of Apple’s documentation — where there is any — suggests searching for the DocumentMetadata.plist. Which makes sense but with two significant drawbacks: every file that you’re looking for now has exactly the same name; and the modification date is the creation date of the document rather than the time of the last update.

This means that you can’t sort the documents alphabetically or by modification date using only the metadata predicate. To get the names you need to listen for updates, copy them elsewhere and then butcher the file name, that is removing the last component and possibly the file extension.

To get the last modification date you probably need to open the document and do a Core Data query. This sounds pretty straight-forward but, again, there are difficulties. Remember that NSMetadataQuery tells us what’s available in iCloud rather than what has been downloaded onto the current device. Just because the query tells us the file is in iCloud doesn’t mean that you can open it immediately.

UIDocument helps us a bit here: if you ask to open a document it will download it if necessary. However there’s a big difference between opening a local file and downloading one over the network and then opening it. Also remember, at this point we’re not opening it as the result of a user request. We’re just trying to find the last modification date so that we can sort the list of documents conveniently.

None of this, of course, is impossible. It’s just a lot of faff for something that pretty much every app that wants to use UIDocument must have to go through.

Okay, so we get all that done. We’re good to go now, right? Not quite.

Part of the idea of using a UIDocument was that it would appear as a, well, document. But that whole thing about what NSMetatadataQuery “sees” comes back to haunt us.

The short, weird version is that if you configure the application to look for DocumentMetadata.plist, then that’s what is seen in the Settings app. Not very helpful as all the documents will all have the same name.

On the other hand you can configure the app to “know” about the document type. This means that the Settings app understands that they’re document and displays them with the correct “file” name. Unfortunately then the app can’t see the documents properly. Specifically, you can search for the document by name — which is nice — but you can’t actually open it. It’s odd and I’m not entirely sure what goes wrong, but when you call openWithCompletionHandler: it never actually calls the completion handler and the document never becomes available for use. (I initially thought that I just wasn’t being patient enough. I later accidentally left the app running for over two hours and the completion handler still never ran. That convinced me that it wasn’t a patience thing.)

I convinced myself that this couldn’t possibly be how it was supposed to work. My question on Stack Overflow didn’t get any answers and a reply to another, similar question said that the behaviour was “by design.”

I think it’s just broken and that no one is really using it. Either that or there’s a secret handshake that you have to give to the right person at WWDC.

So what’s shipping? Pretty much none of the above. I read about the new iOS 7 methods of Core Data – iCloud syncing and liked what I saw. Additionally iOS 7 comes with a few more APIs with better error handling hooks. This made me happier shipping with Core Data syncing. Just using “raw” Core Data meant that I could simplify a lot of code, use NSFetchedResultController and remove a bunch of the more fragile iCloud code (mostly NSMetadataQuery). While I was quite pleased with the KVO code I wrote, having far less code overall is a much bigger win.

And, in case you were wondering, I also de-scoped the Mac app and integrated Dropbox support instead.

But the bottom line is that this is all a lot harder than it should be. My concerns originally were around error conditions — something that has been very weak in iCloud since it’s introduction in iOS 5 — but it quickly morphed into questions about how it’s all supposed to work at all.

I once quipped on Twitter that you can tell which APIs are the ones Apple uses themselves as they’re the well designed ones. I think it’s pretty clear that Apple don’t use UIManagedDocument.

NSFetchedResultsController and iCloud

This took me a while to figure out so I thought it was worth blogging about. The short version: I’m using Core Data with iCloud syncing and it works… mostly. When starting up for the first time – when there is already data in iCloud –  none of the data appears in a table view, but restarting the app correctly displays it.

I know what you’re thinking: you’re not merging the updates into the right managed object context. Nope. Sorry. Thinking that was the problem is probably why it took me quite so long to track the real problem down!

So, what does the problem look like?

I set up my Core Data stack in the app delegate. Part of that includes connecting to iCloud:

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"XXX.sqlite"];
    NSDictionary *options = @{
                              NSMigratePersistentStoresAutomaticallyOption: @YES,
                              NSInferMappingModelAutomaticallyOption: @YES,
                              NSPersistentStoreUbiquitousContentNameKey : @"XXX"
                              };

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                   configuration:nil
                                                             URL:storeURL
                                                         options:options
                                                           error:&error]) {

The app delegate passes the managed object context through to the main view controller which then uses it to create a NSFetchedResultsController:

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"XXX" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"someTimestamp" ascending:NO];
    NSArray *sortDescriptors = @[sortDescriptor];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                                                managedObjectContext:self.managedObjectContext
                                                                                                  sectionNameKeyPath:nil
                                                                                                           cacheName:@"Master"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

	NSError *error = nil;
	if (![self.fetchedResultsController performFetch:&error]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
	    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
	    abort();
	}

(Again, this is pretty much Apple-standard boilerplate code –  nothing clever going on here.)

But what I found was that when there was already data in iCloud, the records did not automatically appear in the main view controller.

Eventually I found that this was not a threading issue – merging the changes into one context and trying to read them from another – by adding an explicit fetch request on a “debug” button. Doing this I could see the new data, even though the fetched result controller could not.

In my app delegate I listened for a number of notifications: NSPersistentStoreDidImportUbiquitousContentChangesNotification and NSPersistentStoreCoordinatorStoresWillChangeNotification. My expectation was that NSPersistentStoreCoordinatorStoresWillChangeNotification would fire before switching from the fallback store to the “real” one and NSPersistentStoreDidImportUbiquitousContentChangesNotification would fire when the new data was available.

I was half right. NSPersistentStoreCoordinatorStoresWillChangeNotification fired on a background thread, so I used GCD to ping it onto the main thread and reset the context.

But NSPersistentStoreDidImportUbiquitousContentChangesNotification didn’t fire at all. I guess the objects didn’t change as such, they just became available, which feels like a slightly false distinction to me.

So my next guess was to fire the fetch request again. The data was visible in the main threads context so surely this would find the data?

Nope. (And don’t call me Shirley.)

I was getting pretty lost at this point so I ended up just semi-randomly stopping the code and looking around in the debugger.

And, long story short, I realised that fetch requests have a reference to the persistent store in them – check out the affectedStores method. This meant that the NSFetchedResultsController was happily, and correctly, reporting on the empty and no longer used fallback store and completely ignoring the new and fully populated iCloud store.

The simple solution was to listen for the NSPersistentStoreCoordinatorStoresDidChangeNotification and create a completely new fetch request.

- (void)storesDidChange:(NSNotification*)notification {
    self.fetchedResultsController = nil;
    [NSFetchedResultsController deleteCacheWithName:@"Master"];
    [self.tableView reloadData];
}

(I did think of just adding the new persistent store to the old fetch request but I wasn’t sure that this would create the refresh anyway and, given the frequency with which this is likely to happen, I thought it would be cleaner just to start from scratch.)

These weird problems almost always boil down to just a couple of lines of code. This time was no exception.

What to do?

There have been a few blogs recently about people finding their true vocation and discovering that it’s not developing software. This is not a “me too” post. I do still develop software for a living and I don’t intend becoming a writer or anything else any time soon. But like most people (I assume) my career has taken turns that I never would have imagined when I started out.

In fact when I was at school I took quite some time trying very hard not to be a software developer for a living. I took geography rather than the rather more obvious (if you know me) chemistry because I wanted to be a pilot. I was so determined to keep programming computers as a hobby that I almost took woodwork instead of computer studies when I was fourteen.

Even when I went to university a few years later I tried (and failed) to read maths. After graduating with a Computer Science degree I fell into a job in software in many ways because I wasn’t sure what else to do.

If this sounds negative it’s because that’s what I was thinking at the time. With hindsight I’m glad that all the effort I spent avoiding my current career didn’t pay off.

The job I took turned out to be a lucky break in some respects. It was at a medium sized consulting company which allowed me to work in lots of different positions on lots of different projects in a relatively short period of time. The effect of this was that I was able to mentally break up the job “Software Developer” into aspects that previously I would have conflated.

What I learned is that I enjoy creating stuff more than managing people. That I’m better at sketching designs on a white-board than I am at testing the resulting code. That I like to make things that are useful rather than just architecturally beautiful. And that I like working with end users, even when they ask for the impossible or contradictory things. (Okay, not exactly at the time they request it but you get the idea.)

In practice this means that I seek out roles that are broader than a stereotypical developer ((I think it’s fair to say that the responsibilities of a “developer” vary more from job to job than that of, say, “accountant.”)) and certainly require more than just coding. Hard-core developers may sneer at the fact that the most common job title I’ve had over the years is some variation on “Consultant” but I actually quite like that it means very little. Under the same title I’ve done everything from development to pre-sales consulting to business analysis.

The point, of course, is not that this is The Right career, only that considering “development” as a single activity wasn’t a helpful way of thinking about what I wanted to do. By breaking down the role into its constituent parts I’ve been able to get a balance of variety and control that I’m happy with most of the time.

Put another way, I’ve been functionally decomposing my career and optimising it for years. I guess I really am a developer at heart.

Familiarity Breeds Contempt

This week I did a presentation at the London iPhone Developer Group meeting. Given my experience with using lots of APIs, I thought it might be a good, if dry, topic. I tried to spice it up by complaining about lots of them and trying to condense that negativity into some useful lessons to take away.

Most of the other discussions of this subject that I’ve seen focus on designing libraries but I thought the same lessons could be applied to all kinds of interfaces, from Objective C libraries to REST API’s for connecting to web services. (I don’t mean to suggest that the focus of the two articles I link to is wrong. They’re both very much worth reading.)

You can see a PDF of the slides here (though they might not make much sense without what I was saying at the time), but the gist is as follows:

  • Design your APIs around use-cases. Many appear to be designed around “how can I made the data I have available.” This is the wrong way round
  • Clients need to access data in a predictable, reliable way. Being clever accepting any old junk and trying to do the right thing is often not the right thing to do
  • Communicate how it works and how it’s going to change clearly. Examples and sample code are always useful
  • Think about error cases. “Something went wrong” is not a good error message
  • Think about the devices that people are likely to be accessing your service from. Mobile apps have latency, bandwidth and CPU constraints that desktop computers and other servers do not. The iPad 4 has more resources to throw at a problem than an iPhone 3GS. Your code might need to work on both
  • Be consistent. Make your API look like other, similar APIs and use the patterns of the technology you’re using. That means delegates and return codes for Objective C, inheritance and exceptions for C#
  • And, most importantly, use your own API. Don’t keep special “secret sauce” for your self. How else are you going to know whether it works than by actually using it?

Ideally I’d end a presentation (or blog post) with salient advice on the best way to do something. This is an exception. I don’t think there’s a one-size-fits-all solution and I’m generally weary of Best Practice guides.

So I’ll end by noting that poor APIs result in poor applications. It’s worth investing the time and energy in doing it well. Your users and your future self will thank you.