MNCoder

Its been about 3 weeks, but I’m finally done with a piece of work that will be used (hopefully) in the iCloud capable version of Mindnode.

MNCoder is what I’d call a clever hack using NSKeyedArchiver and NSKeyedUnarchiver to help with portability of certain Apple classes between iOS and the Mac. If you worked on both platforms, you’d know that iOS has its own implementation for colors and fonts. With iOS 4 this has been extended to NSAttributedStrings that take Core Text attributes instead of the nicer AppKit additions to NSAttributedStrings.

While I’d admit this is a somewhat complicated way of going about things, 2KSLOC to be exact, I figured this was the most straightforward and intuitive way to help people understand and possibly contribute additional code in the future.

What MNCoder does is that it uses a neutral platform independent NSCoding compliant object to store the base attributes that is needed to reconstruct an equivalent on either platform. Using #ifs, the object will give you the appropriate object. Adding to the system is NSCoder which helps with the finding and replacement of objects at runtime when doing serialization.

Its pretty much like old school language translation. Translate your source language into a intermediate version and then translate that to the target language. Nothing too fancy and easily understood.

The work is released under a BSD license which Markus has nicely given his approval of so here’s hoping it’ll have more contributors as it goes along.

Nice side effect of this is that I’ve had extensive time with Core Text and I’d say its pretty fun.

A little advice to companies

Before you engage a developer to build a mobile app for you, consider the following points,

  1. Are you shoving your web page into an app?
  2. Are you providing a catalogue of products/services/etc. with no useful way to purchase them beyond being just a showcase?
  3. Are you adding a “game” so that people will actually use your app?
  4. Are you using the app as nothing more than a marketing effort?

If you have answered yes to the above, here’s some cost saving advice.

    Don’t do it.

    A Core Data Primer

    Everyone’s first encounter with Core Data would be through books and the occasional glance at the documentation. No one tells you what are the base tips in bullet points that you need to know. Having worked on Core Data for the past 9 months, I thought it’ll be a service to the community to at least commit something to Google’s memory.

    • Everything except NSManagedObjectContext is thread safe.
    • Create NSManagedObjectContext in new threads prior to using them. Pass them the NSPersistentStoreCoordinator of any NSManagedObjects across threads is fine.
    • NSManagedObjectID is your friend. Always use it if you are doing threading.
    • NSManagedObjectID is sometimes temporary. Use obtainPermanentObjectIDs to ensure that they are permanent.
    • Getting a permanent ID might cost disk access so use wisely.
    • Process cross context saving on the thread that the NSManagedObjectContext was created.
    • Instrument’s time profiler is your friend to find where Core Data calls are taking a long time.
    • Additionally, you can also get SQL statements that are generated as debug messages in console by turning on a flag.
    • Use as little relationships as possible when fetching objects. Easier to fetch criteria based on the actual operating object and have the fetch also fetch all relationships.
    • Sometimes it is easier to spin off a thread to fetch results and process them before calling the completion block with results.
    • Have a manager to handle all Core Data fetching of objects instead of being smart and trying to have individual managed object subclasses handle everything.
    • NSFetchedResultsController is sometimes a bitch when sending notifications of changed content. Don’t use UITableView’s reloadSectionsWithAnimation and its siblings when crashy happens.
    • Don’t look into [NSManagedObjectContext registeredObjects] to get objects back. They might already have been deleted but still cached. Stupid stupid me.
    • Always test Core Data performance on device.
    • Always do fetches on entities that you are filtering criteria for then use inverse relationships that are prefetched to get the data you really want (Basically think topsy turvy; less database joins the better because this is an object graph).