Monday, June 27, 2011

Versioning Core Data Models and Unit Testing with Xcode 4

Today at my day job I got to create a new version of a Core Data model. The Good News: automatic migration really does Just Work in the simple case of adding a new attribute (column) to an entity (table). The Bad News: Unit Tests do not necessarily automatically get the new version of the model.

For reference, I'm using Xcode 4.0.2, build 4A2002a. Also using Google Toolbox for Mac and OCMock for unit testing.

For some reason, my unit test target (we're using Google Toolbox for Mac and OCMock for unit testing) was originally set up with the following files targeted for various build phases:

  • Compile Sources: MyModel.xcdatamodel (the original version, underneath the .xcdatamodeld directory)
  • Copy Bundle Resources: no model

After creating the new version of the data model, we really want the .xcdatamodeld (the whole directory structure that knows about all versions) to be what gets compiled / bundled.

  • Compile Sources: MyModel.xcdatamodeld
  • Copy Bundle Resources: MyModel.xcdatamodeld

So I had to delete MyModel.xcdatamodel from the Compile Sources build phase and add MyModel.xcdatamodeld. The really weird thing was I could not get Xcode to add the file using the add dialog in the "Choose items to add" dialog that the plus sign brings up.

Note: to see the "Choose items to add" dialog I'm referring to in Xcode 4, do this:

  • Click on the Project name in the Project navigator
  • Click on a Target
  • Click on "Build Phases" at the top of the project info section
  • Expand the "Compile Sources" phase
  • Scroll to the bottom of "Compile Sources" and click on the "plus" sign (+)

Using this dialog, Xcode will allow you to select any of the .xcdatamodel files, but not the .xcdatamodeld. The only way I could get the .xcdatamodeld file in "Compile Sources" (and "Copy Bundle Resources") was by clicking on the file in the Project navigator and dragging it into the build phase. Then it worked like a charm.

One other bit of weirdness: A lot of blogs that talk about versioning Core Data models don't mention how to set the selected version in Xcode 4. To do this:

  • Select the .xcdatamodeld file in the Project navigator
  • Open the Utilities pane (in the upper right corner of Xcode; see image)
  • Select the current version from the Versioned Data Model section of the File Inspector (see image)

Final note: The app pictured in the images, TripCents, is not my current client's app; it's one of mine.

Thursday, June 23, 2011

Mac Pro Tip: macerror

Ran across an obscure error code working on an iOS app at my day job. It turns out there's a utility on the Mac that will give you a little more to go on than some random negative integer: simply run
macerror [error code]
to get a (slightly) more descriptive version. For instance, I was getting error code -25299 trying to add an entry to my app's keychain; macerror reports that as errKCDuplicateItem.

[app next]: TripCents is now in the iTunes store!

My latest app, TripCents, is now available. It lets you store a collection of named trips and calculates the approximate cost of gas, given the distance for each trip, your car's estimated gas mileage, and the current local cost of gas. I wrote it to help me gauge how much to budget for gas each month, and also to educate my kids as to how much money we actually spend shuttling them around town.

I'm particularly happy about the chance this gave me to flex some new iOS developer muscles. Where TreadCalc was essentially a single-screen app with no persistence, TripCents uses CoreData for persistence, has actual multi-page navigation and editable forms, and it renders its views using custom UITableViewCells. It also offers a lot of opportunity for incremental improvements, such as adding the ability to use Google's APIs for geocoding and directions, and MapKit to render geocoded destinations nicely.

You can read more about TripCents on my RuppWorks, LLC website, or if you just can't wait you can go straight to the store.

Friday, June 03, 2011

Mac Pro Tip: Preferences .plist files

I love my new MacBook Air 11". Used it for most of my flight from Atlanta to Chicago today (about 1.5 hours flying time), and for once didn't have to worry about the guy in front of me leaning his seat back all the way into my lap. Also had a reported ~5.5 hours of battery time left when I had to shut down. The only thing I would do differently next time is get maximum RAM (currently sporting 2GB versus a potential max of 4GB).

When I'm at home, I run the MB Air in clamshell mode connected to a 20" cinema display (old school, baby; that's how I roll). Works great, everything displays where it should in either mode.

Except ...

There's this one app, RSA SecurID, that I occasionally need to connect to ThoughtWorks' sites. And it is decidedly not smart about repositioning itself. I usually have it dragged down out of the way, to the bottom right corner of the cinema display, but today while traveling I found out it always stays off the screen, even without the cinema display connected. Exposé will show it to me when I switch to the app and Show Application Windows, but when I click on it, it zips back off to the (now non-existent) bottom right corner of the cinema display. Restarting does not help, nor does gathering windows nor detecting displays in the Displays settings panel.


So I had to resort to opening the .plist file for the app (located for me at ~/Library/Preferences/com.rsa.Software Token\Desktop.plist) and manually updating its two properties: LastXPosition and LastYPosition. Supposedly, .plist files can be edited with any text editor (e.g., TextEdit), but this one seems to be in some binary format; I ended up have to use Xcode's plist editor to be able to make my changes.

Further Pro Tip: Make sure to tab or click out each field that you've edited. If you just type your change in place and save, it will not take.