Tag Archives: Programming

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 developer1 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.

  1. I think it’s fair to say that the responsibilities of a “developer” vary more from job to job than that of, say, “accountant.” []

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."

Programming Is Hard

It’s hard to explain to someone who is not already a programmer the kinds of things that you have to do when building an application. The thing you’re trying to explain is often very abstract and the answer frequently would involve lots of code.

That’s why I thought this particular problem might make an interesting discussion. In talking about this very simple problem we can talk about the things that developers deal with every day and, hopefully, the process can be followed by most people who have used an iPhone (or, actually, any computer). You won’t be a programmer at the end but you might have a greater appreciation for what happens behind the scenes.

The basic problem can be seen in this screen shot.

The login button is a toggle. That is, if I’m currently logged in it says “Log out.” And when I’m not logged in it says “Connect,” which is “log in” in Facebook parlance. A subtlety that you might not ordinarily notice is that when the user clicks the button, the keyboard should move out of the way when it’s not needed and come back again when it is.

There are two basic cases to consider:

  • When I’m not already logged in. In this case pressing the button opens the login screen and the keyboard should shift out of the way.
  • When I am logged in, pressing the button just logs me straight out. In this case the keyboard can stay where it is.

Easy, eh? (That’s what I thought when I started, too.)

Let’s sketch out the code.

when the button is pressed
  if I'm not logged in then
    make the keyboard move out of the way
    log in
  else
    log out

This is called pseudo code because while a computer can’t actually execute it we’ve broken down the processing into the required basic steps. You’ll have to trust me when I say that the real code (called Objective-C) isn’t terribly different.

Not so hard.

Except… you didn’t really think it would be that easy, did you?

It turns out we’re missing one important detail from our algorithm.

One thing we do a lot when programming is use pre-existing components (standing on the shoulders of giants as Isaac Newton, or Oasis, would have it). When you write a component you’re going to come at the problem with some specific ideas of how it’s likely to be used. Hopefully these ideas are the most common ones as this will make everyone else’s life significantly easier.

In this case, our button — a pre-existing component that I didn’t write — is a clever one. It already “knows” how to log in and log out of the service. This sounds like a great time saver and it simplifies our algorithm to just this:

when the button is pressed
  if I'm not logged in then
    make the keyboard move out of the way
  else
    do nothing

Only, it turns out that that doesn’t work.

Why not? Well, the implicit assumption in the above pseudo-code is that it is run first, that is, before the instruction to log us into or out of the service. But if the button logs us out before any of my code is run then no matter whether I was logged in or not before I pressed the button, the above code will find that we’re logged out and move the keyboard out of the way.

When you’re writing a user interface you find dozens of these tiny little details getting in the way of what you’re trying to do. Any non-trivial screen will have lots of these little problems, and the worst thing? No-one will ever know. If you do your job well no user will ever see these little glitches.

Talking of which, how do we eliminate the anomaly that we’ve just found? The solution is pretty simple. At the moment we’re trusting that the button “knows” whether we’re logged in or not. Instead, we’re going to have to take responsibility for doing that as well. That adds a little bit of complexity but isn’t too scary:

  • When the screen opens we need to check whether we’re logged in or not and remember that. In Objective-C we call that a “variable,” but really that just means something that we’re going to store and access again later
  • Later, when the button is pressed we can use the following pseudo-code:
    if the value I saved says that I'm not logged in then
      make the keyboard move out of the way
    else
      change the stored value to "not logged in"
    

  • When I’ve finished logging in — remember I could press the cancel button in the log in screen — change the stored value to “logged in”

And that’s it, we’re done. We have a working version of the log in button.

The final point I’m going to make here is that I ended up discarding all the code above. It just didn’t work as well as I wanted and I ended up implementing it in a completely different way. And this really is the kind of detail that you never notice. A good chuck of any programming project is prototyping, building mock-ups and other activities that don’t directly end up in any shipping product. All this discarded work — which does, at times feel like a waste of time — is designed to make the product better.

Some people who have never programmed say things like “there’s nothing complicated there” or “it’s only a button!” Hopefully this post has shown that even a simple button can be far more work that it initially seems.