Tag Archives: Programming

Learning Swift

Swift is a new programming language designed by Apple for development on OS X and iOS. I thought that I should try to learn it a little so I decided to convert a non-trivial collection of classes from one of my apps (www.cut) into Swift. I always find it better to work on a real project rather than just to play around with things aimlessly. Also, by re-working an old project, I knew that all the problems I would find would be language related rather than anything to do with the architecture.

The classes are also data related rather than being UI, so it is mostly a test of the language itself rather than how it interfaces with Objective C.

First impressions are good. Swift is mostly nice and consistent, which although sounding like damning with faint praise, is actually a compliment. I read a little of the language guide and dove straight in. A lot of the attempts to get the following right were me just typing stuff, guessing the syntax rather than looking it up.

Quite by accident I think my code sample inadvertently shows an area of strength for Objective-C and weakness for Swift.

The idea of the code is that it reads a Plist, instantiates a class based on that configuration and fills in a number of properties.

The first half of the code looks like this:

        NSError* error = nil;
        NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"XXX" ofType:@"plist"];
        NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath];
        NSDictionary *temp = (NSDictionary *)[NSPropertyListSerialization propertyListWithData:plistXML
                                                                                       options:NSPropertyListMutableContainersAndLeaves
                                                                                        format:NULL
                                                                                         error:&error];
        NSArray* values = [temp objectForKey:@"Entries"];

This was pretty straight forward to convert into Swift, though the type system gave me issues:

    let plistPath =  NSBundle.mainBundle().pathForResource("XXX", ofType: "plist")
    let plistXML = NSFileManager.defaultManager().contentsAtPath(plistPath)

    var error:NSError? = nil
    var format:CMutablePointer<NSPropertyListFormat>? = nil
    let immutable:NSPropertyListReadOptions = 0
    var pList = NSPropertyListSerialization.propertyListWithData(plistXML,
        options:NSPropertyListReadOptions(NSPropertyListMutabilityOptions.Immutable.toRaw()),
        format:format!,
        error: &error) as NSDictionary

Getting the options property seems very clumsy; I’m sure that there must be a better way of doing it.

I had a real problem with the in/out parameters format and error. Not only was the documentation confusing but the Swift Playground kept crashing making it difficult to distinguish between what I was doing wrong and where the compiler itself was messing up. It’s also a bit odd that, though both are in/out parameters, that they both need different methods to extract the values.

(To be fair, this is a beta and it is the first version of a whole language and compiler. I mention the crashes not because they’re unexpected or even especially bad, just as an honest description of the difficulty I had.)

The next section, using the data in the plist, was much more problematic. The code looks like this, but I’ve trimmed a lot so what we have here isn’t terribly useful now!

        proxy = nil;
        for (NSDictionary* i in values) {
            if ([thing isEqualToString:[i objectForKey:@"Class"]]) {
                dynamicClass = NSClassFromString([i objectForKey:@"BaseClass"]);
                proxy = [[dynamicClass alloc] init];
            }
        }

I didn’t do the straight conversion. A few more years of Cocoa programming allowed me to notice an optimisation:

    let valueList = values.filteredArrayUsingPredicate(NSPredicate(format: "Class = %@", value))
    let valueData = valueList[0] as NSDictionary

This same approach would work in Objective-C.

Next I tried:

  let dynamicClass = NSClassFromString(valueData["BaseClass"])
  let proxy = dynamicClass()

The first line works as expected. The second line doesn’t compile.

Is there anything else that we can do with dynamicClass? Let’s see. It’s an AnyClass which is a type alias for AnyObject.Type. Which doesn’t really help.

I tried casting it to a base class but no matter what I tried I couldn’t alloc/init it (in Objective C terms).

Josh Smith figured out how to do it by creating a factory class in Objective-C.

I tried (and failed) to get it to work by calling some of the Objective-C runtime directly:

var bytes:Byte[] = [0,0,0,0]
let b = objc_constructInstance(a, &bytes)

But the second line doesn’t work when using ARC. (To be fair, Xcode struck through the definition so I didn’t have much confidence that it would work!)

So that leaves Josh’s call out to Objective-C to be the best method that I’m aware of.

In the end I just used a switch statement to select between the relatively limited number of options that I had to choose between. Not as clever, but maybe that’s a good thing?

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.

Glitches

It started with this image. Or rather the glitch that you can see in the middle of the screen.

It’s one of the screens in a new app that I’ve been developing. There’s lots of hard stuff in there but this is the first problem that has really stumped me. What it appeared to be was this: a text view (UITextView) on a table (UITableView) showed a nasty glitch when you tried to place the curser in the text box.

First thoughts:

  • Transparency
  • Scrollview (UITextView) within a scrollview (UITableView)
  • Image background

So I switched off the transparency. (No effect.) I switched off scrolling while editing. (No effect.) I made the background boring. (No effect.)

I was stumped.

I showed it to some guys at the London iOS Developer Group meeting. They too were stumped. (This was a bit of a relief. It meant that I wasn’t doing anything completely stupid, which is always a risk.)

So I tried writing a question for Stack Overflow. And, as I often do, I stumbled across the solution.

Note that the text view has a small border and rounded corners? Yup, that’s the culprit. Or at least, some of that code is. Here are the two lines that do it:

self.layer.cornerRadius = 5;
self.layer.shadowOpacity = 0.5;

(There were quite a few other lines adjusting the layer too, which is what took the time to narrow down.)

It was nothing to do with the table view or the text view per se. It wasn’t even any of the visible transparency effects.

Of course, in the screen I have no need for a shadow, indeed you can’t even see one, so the solution was easy. Quite why this combination causes such a weird effect have no idea, but I’m glad that I found the solution.

(I raised a bug report with Apple: rdar://11041657.)

My delicious.com bookmarks for February 8th through February 20th

  • An Attribution Failure Theory – "Credit is easy. Well, mostly easy. It might have been hard to get the format of citations right at first in school when we were writing papers, but the act of citing is easy. You just do it. Yet, people all over the Internet don’t."
  • You Are Not Ruthless Enough – "Here’s the thing: you are not ruthless enough. You are certainly not ruthless enough to your objects, and you probably need to be more ruthless to yourself." Programming Is Hard, Part 381.
  • You Will Never Kill Piracy, and Piracy Will Never Kill You – "The seven step, ten minute download process (which will be about ten seconds when US internet speeds catch up with the rest of the world) is the real enemy the studios should be trying to tackle."