Adding an Attribute to a Core Data Entity in Xcode 4

July 31, 2011

I wanted to add an attribute to one of the objects I manage using Core Data in my iPhone app. Because it’s a simple change, I wanted to use what Apple calls Lightweight Migration–automatically migrating the data when you make a simple change like adding a field.

I had to assemble the steps from a few different places to get it to work, partially because blog posts I found were for Xcode 3, and not even all the Apple docs have been updated for Xcode 4. Here’s the full set of steps that worked for me. For example purposes, I’m assuming your app is called YourApp, and the Core Data model is called YourData.

  1. Don’t make changes to the data model yet!
  2. Run your app in the simulator to make sure it has data set up under the current version of the entity.
  3. Select the YourData.xcdatamodel file and choose Editor > Add Model Version… The default numbering scheme (“YourData 2”) is probably fine.
  4. Select the new YourData 2.xcdatamodel file, select the entity, and add the new attribute. Make sure the right pane is visible (third button above “View” on the toolbar) and the third option within that pane is selected. Either set the attribute to be optional, or set it to have a default value–you have to choose one or the other for Lightweight Migration to work.
  5. Regenerate your model classes by selecting the entity, choosing File > New > New File…, then NSManagedObject subclass. Note: I first created my classes under Xcode 3, and at that time it put the .h and .m files inside of the actual YourData.xcdatamodel file (which is really a directory on the filesystem). Xcode 4 didn’t seem to give me this option, but that’s fine–to me, it makes more sense to store them with the other classes anyway. If you do put your new .h and .m files in a new location, be sure to delete the old ones.
  6. Select the YourData.xcdatamodeld file, go to the right panel, first option, and look for Versioned Data Model > Current Version. Set this to the newer version.
  7. In YourAppAppDelegate.m, find the persistentStoreCoordinator method, or wherever you call addPersistentStoreWithType:… You will probably be passing it nil for options:. Instead, pass this:


    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

  8. Update your app to use the new attribute/property in your entity. You might want to make only small changes at first, in case something goes wrong with your auto migration.
  9. Run your app and test it.

I wrote these steps out after I finished, so please leave a comment to let me know if I missed something and you run into other trouble.


Is iOS 5 Beta Live?

June 6, 2011

Currently, Apple’s iOS Developer page is down, while the iOS 5 Beta is being posted. Here’s a quick Perl script that checks every 5 seconds to see if the page is back yet:


#!/usr/bin/perl
use LWP::Simple;
$url = "http://developer.apple.com/devcenter/ios/index.action";
$size = length(get($url));
while( $size == length(get($url)) ) {
print "Not ready! time = " . time . "\n";
sleep 5;
}
print "Ready!\n";

UPDATE: or you can just pull up this web page.


Delegates, Protocols, and Optional Methods

June 5, 2011

In my iOS app, I have a lot of places where I show a modal view, and that view needs to have access to the view that opened it. To implement this connection, I’m using the concept of “delegates,” where one object has another object that it can call methods on. I created a protocol called ModalDelegate that defined the methods that these modals could call on their parent views. However, the way I implemented this caused a lot of compiler warnings. I just now figured out how to fix these, but the answers were difficult for me to find, so I figured I’d post them here.

First, it was my understanding that using id as a variable type was the standard Objective-C way to keep a reference to an object that can be of any class–the equivalent of the Java class Object, but more widespread in use. However, when I stored my delegate as an id, then tried to call a method on it, I received a warning that that method might not be defined. I could have cast the id to the appropriate type, but that seemed like it shouldn’t be necessary.

So, instead, I changed the type of the variable from id to ModalDelegate, the name of the protocol I created. This seemed intuitive to me from the way Java interfaces are used, and the compiler didn’t reject that variable naming. However, I got a similar warning: that method might not be defined. When I looked into it, I discovered that wasn’t the right syntax to use for a protocol at all. The right type for the variable was id <ModalDelegate>–in other words, an object of any type, but one that conforms to the ModalDelegate protocol. Also, instead of referring to @class ModalDelegate; in my header file, I needed to refer to @protocol ModalDelegate;.

The one remaining warning I was getting after this was that my classes weren’t implementing all the methods on the ModalDelegate protocol. The reason for this was that different views needed to have different methods called on them, and I didn’t want to have a separate delegate definition for each. So there were lots of methods in ModalDelegate, and each class that conformed to the protocol only implemented some of them. Of course, this isn’t how protocols are meant to work, but I didn’t see an alternative. But finally I found it: optional methods on protocols. I just add an @optional above all the methods that I want to be optional, and then the warnings went away. For my protocol, I actually wanted all the methods to be optional.

I don’t think this is a violation of the concept of the protocol, precisely because it removes all the warnings I had above. My modal view can call methods on its delegate without compiler warnings, because it knows it should have an id and that it may have a method of the appropriate type. The alternative would be to simply have an id and accept the warnings, or else use performSelector:withObject:, but those seem like overkill for the situation I’m in. The other alternative would be to implement each of the protocol methods and leave some of them as empty implementations. But all of these seem like overkill for my situation. With a protocol with optional methods, I’ve clearly defined for the compiler what I’m doing, and its lack of warnings assures me that I don’t have any typos.


My iOS Bookmarklets

May 17, 2011

Bookmarklets are links you can add to your browser toolbar that perform different functions based on the page you’re currently on. They’re the only option for extending the functionality of Safari on iOS.

I’ve added my favorites to a page with instructions linked below. (WordPress for iPad breaks bookmarklets, it seems.)

My iOS Bookmarklets


Set Up a Subversion Server For Free in Zero Steps

April 14, 2011

Want a Subversion server? Your options usually boil down to:

  1. Pay for an expensive hosted solution.
  2. Use an unreliable or crippled free hosted solution.
  3. Wait for your IT department to set one up for you.
  4. Slog through setting one up yourself.

Maybe setting up a Subversion server is easy if you’re a Linux expert, but, if you’re anything like me, there are a million things that can go wrong in the configs, and no online guide gets all the instructions right.

Well, as of now there’s a better solution. I’m posting a virtual machine image that has a working Subversion installation, tied to Apache. Download it, start it, and you’ve got a Subversion server!

It’s a VirtualBox image running Fedora 14. It includes a README file with instructions on how to start and access svn, and add new users. Download it here:

SubversionVM.zip

Unfortunately, I can’t provide any support for this image (I just cobbled it together myself). But I hope it’s helpful!


Duplicating a VirtualBox Hard Disk on Mac Host

November 5, 2010

I’m running VirtualBox on a Mac OS X host, and I had one .VDI hard disk file that I needed to duplicate into three and use them all at the same time. When I tried to load them all into different VMs inside VirtualBox, I got an error that a hard disk with that UUID was already in use.

Turns out that you can’t just duplicate the hard disk file–you need to use a command called VBoxManage to do it. But it took me a while to find out how to run that command on a Mac.

Here’s what you need to do in a console window:


/Applications/VirtualBox.app/Contents/MacOS/VBoxManage clonevdi path/to/yourold.vdi path/to/vditocreate.vdi

It will probably take a while, and it will only update the progress indicator every 10% or so, so have some patience and you should be set. Once the duplicate is made, just create a new VM in VirtualBox, and choose your new .VDI file.


Debugging iPhone Apps

October 27, 2010

This is pretty basic, but I didn’t find this info all in one place, so I figured I’d post it here.

If your iPhone app is crashing, here’s a series of steps you can take to troubleshoot it:

  1. Check your build warnings. Just because there were no errors that prevented execution, doesn’t mean your app won’t crash. One common warning I often have to fix is mistyped method names. Objective-C will compile your code if you call methods on an object that don’t exist, but it will throw an exception at runtime.
  2. Check your Xcode console. Most crashes will show up here.
  3. Check your Mac OS X console. This is found under Applications/Utilities/Console. Sometimes a crash won’t output data in the Xcode console for some reason, but it will output it here.
  4. Check your Diagnostic Reports folder. This is found under /Users/youruser/Library/Logs/DiagnosticReports. When your app crashes in the simulator, it should create a new crash file here. Double-clicking one will open it in the Console app, and it should have info on what line number the crash happened on.
  5. Check your CrashReporter folder. This is for if crashes happen on your device when it’s not hooked up to the debugger. The next time you sync, the crash logs will be copied to /Users/youruser/Library/Logs/CrashReporter/MobileDevice/Your Device Name. You don’t want to bother opening these directly in the console, though–it doesn’t include method names and line numbers. Instead, you want to use a command-line utility called symbolicatecrash to translate the crash log into a version with method names and line numbers. Konstantin Anoshkin’s blog describes the process well–the only change I had to make was that in Xcode 3.2 I now find symbolicatecrash at /Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKit.framework/Versions/A/Resources/symbolicatecrash