Five Lessons Learned from Migrating to iOS Core Data

A couple of weeks ago we decided to fully switch to Core Data for persistent data storage on our iOS apps. This was a bold decision that would bring us more coherent data representations, performance improvements and make future data migrations a breeze…or so we thought. Whilst there certainly were a lot of gains from switching to Core Data it took us a lot longer than anticipated, and we ran into some unexpected issues and limitations. Since we are surely not the last ones moving existing apps to Core Data, we would like to share some of our lessons learned.

Note: This post assumes that you are already familiar with the concepts of Core Data and its classes. If you are new to the subject, we recommend reading the Core Data programming guide by Apple.

Lesson 1: The more you respect MVC, the easier your migration will be

Core Data knows no mercy with developers who disrespect the MVC principles. Because model objects can get deallocated and reloaded at the will of their managing NSManagedObjectContext you can never rely on them being around unless you specifically retain them (which isn’t a good idea). It is thus unwise to set the model objects as the direct receivers of callbacks (for example, image download). Instead, route all calls through the appropriate controller, which manages the NSManagedObjectContext of the data object, and retrieve the data objects at the time when you need them to store the downloaded information. This does not only solve the availability issue but also makes for much cleaner code as you are forced to minutely adhere to the MVC standards.

Lesson 2: Data migrations are a breeze…if you have XCode >= 4.0.2

If you are already partly using Core Data in your application you will probably need to update your data model, and chances are that you need to provide a migration mapper. Luckily there are some great tutorials on the subject out there; however, you can still lose a lot of time if you forget either of the following:

  1. Turn off automatic data migration (when initializing the persistent data store manager, set NSMigratePersistentStoresAutomaticallyOption to NO)
  2. If you are still running XCode 4.0.0, upgrade to at least XCode 4.0.2. Previous versions have a bug that prevents the migration mappers from being placed in the proper location at link time. Believe us, we learned the hard way.

Lesson 3: Multithreading and Core Data can work very well if you plan ahead

Perhaps the most annoying part about Core Data is that, in its current implementation, the two objects you interact with the most (NSManagedObjectContext and NSManagedObject) are both not yet threadsafe. However, there are best practices, using workarounds, for both updating and loading objects on secondary threads. If you familiarize yourself with them before implementing your designs you will find it pretty easy to create concurrent applications using Core Data. Apple has a great guide on Core Data and concurrency which is well worth the read and nicely explains what to do in both situations.

Lesson 4: NSFetchedResultsController is not always useful

In order to make it easier to use UITableView together with Core Data, Apple has invented the NSFetchedResultsController, which manages the NSManagedObjects associated with a particular fetch request and monitors an associated NSManageObjectContext for changes to those objects. While this setup is great if there is only one UITableView being displayed and there are few changes being made to the underlying data objects, we’ve found that using NSFetchedResultsController, under certain conditions, can adversely effect the (felt) performance of your app. When you have data sets with many changes or if there are frequent changes being made to underlying data objects, it is advisable to manually “bundle” those changes and entirely reload the UITableView instead of incrementally reloading the cells affected. If you meet one of those two cases, consider implementing your own update routine and temporarily deactivating the update mechanism of the NSFetchedResultsController by setting its delegate to nil.

Lesson 5: Performance, performance, performance!

To get the best performance out of Core Data keep the following in mind as you sketch up your refactoring:

  • Multiple small queries are slower than one larger query since every call to performRequest: hits the disk
  • Complex filter predicates can significantly hamper the performance of your queries, keep them as simple as possible
  • Fetching relationships is expensive; avoid them if they do not provide a significant advantage. Flatten your data model where you need to load data together.
  • Only store small data objects directly in CoreData, store larger objects in files and only save the path to them in CoreData (eg. images)

We hope these insights will help you when planning your own migration to CoreData. Let us know if you find other valuable tricks for dealing with CoreData!

Thanks for reading!
~The Pulse iOS team

Design Secrets for Engineers

 

If you are a designer like me, you must be asked on a regular basis to “make it look pretty.” The request can stroke your designer ego, making you feel like a design rockstar with super powers to make this world a more beautiful place. This is especially true at startups, where you are one of the few, maybe the only designer there. However, it can also be really annoying–almost degrading at times. Thoughts like “why the hell can’t engineers do this on their own? It’s all common sense” always go through my head. If only engineers knew how to do visual design, designers would have more time to focus on cooler, more exciting problems like future product concepts.

And if you are an engineer, you might wonder how designers pull off their tricks (and why they’re in such huge demand right now). Is it genetic? Do design schools teach them top secret design tips? Or did they make a deal with the devil to get designers’ eyes in exchange for their souls?

Well, I’m here to bring you some good news: engineers don’t need to drink unicorn blood just to be good at visual design. I am a strong believer that good design is a highly learnable skill, like riding a bike, playing a piano or learning Spanish. If you practice often enough, you’ll become better and better at it, and once you’ve got the hang of it, you’ll never go back. I can say this because I too once sucked at design. But then I learned a few tips from my graphic design friends, and a few years later, I could proudly say that I was a design expert. Today, I want to share these not-so-secret tips with you.  The first five are more specific to visual design while the next three are geared towards interaction design.

 

1. Line things up.

Good example: beautiful sites and apps usually have underlying grid behind them.

This rule is the mother of all graphic design rules. Unless you’re recreating the Mona Lisa on MS Paint, please line things up. Our brains just like it better that way. The slightly more advanced version of lining things up is called the grid system, which is essentially lining more things up. Kindergarten kids can do it and so can you.

 

2. Design the white space.

Bad example: this is what happens when you try to fill in your white space with information.

When you’re in an elevator with 15 other people, it’s not so easy to breath…especially when someone farts. When you design a layout or UI, try not to jam too many elements into a page; it increases the chance of having one of the elements stink the whole thing up. Leave some white space for the eye to breathe. I often find myself designing the space in between elements, making sure elements aren’t too far apart or too close together.

 

3. Use designer fonts.

Bad example: use these fonts and designers will make fun of you.

In the design world, there are good fonts and bad fonts. Good fonts like Gotham, Trade Gothic Bold Condensed or Garamond please your eyes and make you feel like you’re having a frosty cold mojito on the beach. Bad fonts, on the other hand, make us designers cringe and feel like we’ve vomited from our eyes. Try to avoid super default fonts like Impact, Curlz, or Comic Sans, to name a few. If you must use a preloaded font, Helvetica and Georgia are two exceptions–they’re classic and restrained enough to be unoffensive.  If you want designer fonts that play nicely with the web, try Typekit. Oh…and please don’t use WordArt. Ever.

 

4. Keep it consistent.

Good example: use pick a few and run with it.

Use no more than two fonts and three colors in your designs. And keep them consistent throughout your sketches. Each time something changes, our brain has to go “whaaaa?” for a moment before figuring things out, so let’s give our brains a rest and keep things consistent. Also, let’s try not to stretch logos or images.  Imagine if someone took your face and stretched it horizontally by 5%. Still happy with the way you look?

 

5. Keep visual hierarchy in check.

Good example: quint your eyes. What do you see?

I don’t know about you, but when I cook, I always do a little tasting from time to time to make sure that my seasoning is on track. When you design, check yourself from time to time. Squint your eyes every now and then and look at the screen. What pops out at you first? What do you see second? Third? Walk away from the screen, then look at it from 10 feet away. Believe it or not, designers and architects do this all the time to keep things in perspective (literally).  It’s a good way to keep yourself from getting lost in little details or adding unnecessary buttons to the screen.

 

6. Set priorities and stick to them.

Bad example: don't allow this to happen in your product.

“Let’s put a help button there just in case the user is curious what’s going on. Oh…and let’s make the button look a little more like a button. And before I forget, can you make that tab pop a bit more?” Sometimes, I wish there was a robot that would bitchslap the one asshole in the room who keeps bringing up corner cases (cases that apply to only one very specific scenario).  Until this bitchslap machine is built, however, we can get by with a list of what’s important and what isn’t, backed by some data if possible. It will save you time and energy, and shut that asshole up.

 

7. Check the Physicality of the UI.

WTF example: imagine your interface lived in a little box. Try not to make impossible things happen.

A lot of what makes a UI successful is how familiar it seems to users when they first encounter it. Most users don’t have exhaustive experience with mobile apps, and will assume that they follow the same rules as the real world. When you’re making design decisions, ask yourself what sorts of physical analogs each element has.  If the UI was to be re-created in the real world, would it make sense?

 

8. Use Keynote.

Best. Prototyping. Tool. Ever.

I love Keynote.  I don’t know how else I would have come this far in life without this magical program that lines things up automatically and makes it easy to make things look good. Beyond just making slide decks, Keynote is a great way to mock up UI flows. Do a quick web search for “Keynote mockup templates” and you’ll find a number of great starting points for building good-looking prototype apps quickly and easily.

 

And remember to listen to others! It’s natural that confidence comes with the thought that you’re right and every one else is wrong. But just admit it: you’re not always right.

Chances are you probably won’t become a design supreme being over night. It takes some practice and confidence that you’ll get good at it. Ira Glass from NPR sums it up pretty well. http://www.mymodernmet.com/profiles/blogs/great-advice-for-creatives.

Just keep repeating “I, too, can be a designer”–eventually you will become one.

 

ps: we are hiring designers and designer-wannabe engineers!

Bringing Location-based Deals to Your Phone

Savvy shoppers have always been on the lookout for new deals, but sites such as Groupon, Gilt City, and LivingSocial have made deal-hunting even more popular. For the last few weeks, we’ve been working hard to make finding great deals easier for our users. By aggregating local deals from these sources, we hope to make them less intrusive (than email alerts) and easy to peruse. It should also be painless to scan deals from several different sites at once by simply adding each of them in Pulse.

Where are the deals?

Since most deal sites are location-based, we want to allow our users see deals that are nearby. The first step is to know where the deals are. We can get a list of cities (either through API calls to the deal sites or RSS feeds provided by them) and store the longitude and latitude of these cities. If the sites are unable to provide a list of cities and/or their coordinates, it is relatively straightforward to scrape the list of cities from their website (with permission of course!) and find the coordinates of the cities through services such as the Google Geocoding API.  Once we have this data, we store the city/coordinate pairs in the Google AppEngine datastore (Figure 1).

Figure 1: City coordinates in datastore

Where is the user?

On GPS enabled devices, location coordinates are relatively easy to come by. A client application can simply query the server with a user’s coordinates (with user’s permission) using an API call such as: http://<server>/api/nearby?long=-73&lat=42&max=10. After some server-side calculations, this call will return a list of nearby cities that should be relevant to the user because they are nearby the location the user just provided.

What is nearby?

Given that we have each city’s coordinates stored on the server and the user’s coordinates from the client application, how do we determine which cities are closest? We use the following algorithm to figure out which cities we should show to the user:

for city in cities:
    dist = math.pow(city.long - user.long, 2) + math.pow(city.lat - user.lat, 2)
    heapq.heappush(result, (dist, city))

The result is a min heap that ranks the cities from the closest to the farthest. We return this list (or a subset of it) to the client application and then allow the user to choose to add deals from a city near them.

The key to making this operation efficient is loading the city coordinates into memory (in our case, into the AppEngine Memcache). This simple optimization works well for any small/medium sized list of locations and turns a resource intensive calculation (that can be quite involved to implement on AppEngine’s datastore) into simple and scaleable operation that requires no datastore calls.

We hope to give our users a better experience by offering the ability to aggregate deal sites in Pulse. This was a short insight into how we implemented this feature.  If you have great ideas that can help further improve this experience, let us know!