iPhone - Beware of case sensitivity when enabling data model versioning
In an app I'm building, I decided it was about time to start thinking about data model versioning as a way to protect user data from database schema changes. Without versioning, every time I updated the app's schema, the user's data would have to be wiped out. Not good.
Any way, I consulted various sources on how to do this, including my beloved More iPhone 3 Development and Apple's Introduction to Core Data Model Versioning and Data Migration Programming Guide. I made the minor changes to my code in the persistentStoreCoordinator and managedObjectModel, and tested in the Simulator. Great, nothing was broken, the changes worked just as advertised.I continued coding, and a few hours later decided it was time to test on the device.
Bummer, I got this error message: 2011-02-10 14:23:12.470 myApp[9241:307] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL initFileURLWithPath:]: nil string parameter'
*** Call stack at first throw:
(
0 CoreFoundation 0x33ac0987 __exceptionPreprocess + 114
1 libobjc.A.dylib 0x3347b49d objc_exception_throw + 24
2 CoreFoundation 0x33ac07c9 +[NSException raise:format:arguments:] + 68
3 CoreFoundation 0x33ac0803 +[NSException raise:format:] + 34
4 Foundation 0x3362b54f -[NSURL(NSURL) initFileURLWithPath:] + 70
5 Foundation 0x33650157 +[NSURL(NSURL) fileURLWithPath:] + 30
6 myApp 0x00003537 -[myAppAppDelegate managedObjectModel] + 138
7 myApp 0x000036fb -[myAppAppDelegate persistentStoreCoordinator] + 302
8 myApp 0x00003407 -[myApp AppDelegate managedObjectContext] + 62
9 myApp 0x0000302f -[iNspectorAppDelegate application:didFinishLaunchingWithOptions:] + 78
10 UIKit 0x3209ebc5 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 772
11 UIKit 0x3209a259 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 272
12 UIKit 0x3206648b -[UIApplication handleEvent:withNewEvent:] + 1114
13 UIKit 0x32065ec9 -[UIApplication sendEvent:] + 44
14 UIKit 0x32065907 _UIApplicationHandleEvent + 5090
15 GraphicsServices 0x33b0ef03 PurpleEventCallback + 666
16 CoreFoundation 0x33a556ff __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 26
17 CoreFoundation 0x33a556c3 __CFRunLoopDoSource1 + 166
18 CoreFoundation 0x33a47f7d __CFRunLoopRun + 520
19 CoreFoundation 0x33a47c87 CFRunLoopRunSpecific + 230
20 CoreFoundation 0x33a47b8f CFRunLoopRunInMode + 58
21 UIKit 0x32099309 -[UIApplication _run] + 380
22 UIKit 0x32096e93 UIApplicationMain + 670
23 myApp 0x00002fb3 main + 70
24 myApp 0x00002f68 start + 40
)
Looking at the error trace, something was happening in the managedObjectModel function, and the error message in the first line indicated that the NSURL string was nil. The offending block of code was this: NSString *path = [[NSBundle mainBundle] pathForResource:@"Datamodel" ofType:@"momd"];
NSLog(@"path: %@", path);
NSURL *momURL = [NSURL fileURLWithPath:path]; I added the NSLog line to print out the contents of the `path` variable, and discovered that it was not nil when running in the simulator, but nil when running on the device. I went to have a look at the application assets in
/Users/peter/Library/Application Support/iPhone Simulator/4.2/Applications/F2854B27-4750-4DC8-8CB6-A22B036F5DC9\myApp.app
by right-clicking and selecting "Show Package Contents", and noticed that the data model versioning directory was named `DataModel.momd`.
However in my code, the path variable was `Datamodel` (loading a resource of type `momd`), whereas the directory containing the model versions was `DataModel`.
Yeap, this was another case of the simulator and the device behaving differently, this time in how they handle file name cases.
NSString *path = [[NSBundle mainBundle] pathForResource:@"DataModel" ofType:@"momd"]; and ran on the device, it worked.
