The answer by Shezi helped a lot but like others here: Preloaded Core Data Database in ios5 with UIManagedDocument and here: Pre load core data database coming up black with UIManagedDocument I had problems.
Firstly, behaviour on the simulator is noticeably different from behaviour on a device. If you instantiate the UIManagedDocument using initWithURL
where the URL points to the app bundle, you'll get a warning that this is a read-only directory in the console when running on the device, but no such warning appears on the simulator. Permission handling seems to be quite different and you can get different results.
The docs suggested that migratePersistentStore:toURL:options:withType:error:
should be used instead of [doc saveToURL:newURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success){}]
I spent a long time trying to get this to work but had a lot of trouble getting a pointer to the persistent store. Even though my app worked fine for read-only operations after following Shezi's solution, the persistent store coordinator kept on giving me a null pointer for the persistent store. This happened when I tried both – persistentStores
(which returned an empty array) and
– persistentStoreForURL:
If anyone can explain why this happened, I would be interested. The annoying thing was that it would sometimes work on the simulator, but when I tested on the device, it failed.
In the end, I changed things around and copied the bundle folder into the documents directory first, before instantiating the UIManagedDocument. This seems to have done the trick. Here's the code. It assumes that your UIManagedDocument is a property of the class. I put this in the viewWillAppear method of the initial view controller. Remember that you need to open the document if you instantiate using a URL containing an existing persistent store.
if (!self.yourUIManagedDocument) {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"yourUIManagedDocument"];
NSString *documentsFolderPath = [documentsDirectory stringByAppendingPathComponent:@"yourUIManagedDocument"];
NSURL *documentsUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
documentsUrl = [documentsUrl URLByAppendingPathComponent:@"yourUIManagedDocument"];
if (![[NSFileManager defaultManager] fileExistsAtPath:documentsFolderPath]) {
NSError *error = nil;
if([[NSFileManager defaultManager] copyItemAtPath:bundlePath
toPath:documentsFolderPath
error:&error]) {
self.yourUIManagedDocument = [[UIManagedDocument alloc] initWithFileURL:documentsUrl];
[self.yourUIManagedDocument openWithCompletionHandler:^(BOOL success) {
}];
} else {
NSLog(@"%@", error);
}
} else {
self.yourUIManagedDocument = [[UIManagedDocument alloc] initWithFileURL:documentsUrl];
[self.yourUIManagedDocument openWithCompletionHandler:^(BOOL success) {
}];
}
} else if (self.yourUIManagedDocument.documentState == UIDocumentStateClosed) {
//Document is closed. Need to open it
[self.yourUIManagedDocument openWithCompletionHandler:^(BOOL success) {
}];
}
Of course, the above assumes that you have already generated the database using the simulator and copied the directory into the app bundle in exactly the way Shezi described. Any comments or suggestions for how to improve the code are welcome. I'm still learning here.