Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIManagedDocument can only read documents that are file packages

My app is using a core data SQLite database. I would like to enable my users to use iCloud to sync it between devices - and I was thinking I could use UIManagedDocument.

I subclassed it, following Apple's documentation, and it is works when a new persistent store file needs to be created. However, when I try to use it to open my old persistent store file, I get the following exception thrown error:

"UIManagedDocument can only read documents that are file packages"

Does this mean that I need to migrate the old persistent store to a new store managed by UIManagedDocument? If so, do I need to do this manually (i.e. read each record one-at-a-time from the old store and write it into the new one)?

Thanks in advance!

like image 250
montuno Avatar asked Dec 09 '11 13:12

montuno


2 Answers

UIManagedDocument creates packages(folders) rather than atomic stores. The store is still there but its buried in the package. If you right click on the file that is created in your Documents folder in the simulator you'll be able to see the structure. The default is

mydocument.foo
   -> StoreContent
      -> persistentStore

What you need to do is create a new extension for your app file type so for example if your database extension is .myappdb you need to create a new document type in your project settings which might be .myappdbw. You can copy all settings from the entry for .myappdb

Next at the point where you handle opening your legacy document at mydocumenturl instead of passing that to your persistent store co-ordinator you create the directory structure above.

NSURL *newurl = [[mydocumenturl  URLByDeletingPathExtension] URLByAppendingPathExtension:@"myappdbw"];
NSURL *desturl = [newurl URLByAppendingPathComponent:@"StoreContent"];
[[NSFileManager defaultManager] createDirectoryAtURL:desturl withIntermediateDirectories:YES attributes:nil error:NULL];
NSURL *finalurl = [desturl URLByAppendingPathComponent:@"persistentStore"];

and then move the legacy database into the folder system you have created

[[NSFileManager defaultManager] moveItemAtURL:mydocumenturl toURL:finalurl error:NULL];

and then you can pass the bundle url to UIManagedDocument

UIManagedDocument *doc = [[UIManagedDocument alloc] initWithFileURL:newurl];

A link which will be useful for the iCloud integration is

http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-iCloudCoreData/_index.html

Its all a bit mysterious as the most of the promised sample code has failed to appear so far but on the other hand its mostly fairly simple to deduce. Have a look at WWDC2011 sessions 107,116 and 315 for more hints.

But note that if you are going to use this method for migrating your legacy docs DONT set the NSPersistentStoreUbiquitousContentNameKey at point you migrate because the package changes when you do. The doc above describes it quite well.

like image 69
Warren Burton Avatar answered Nov 14 '22 11:11

Warren Burton


Thanks for this tip. I think I found an even simpler solution.

I just create a new UIManagedDocument with a different filename than my old persistent store location.

In my subclassed UIManagedDocument, I override the configurePersistentStoreCoordinatorForURL method and do the migration once there:

- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)storeURL ofType:(NSString *)fileType modelConfiguration:(NSString *)configuration storeOptions:(NSDictionary *)storeOptions error:(NSError **)error
{
    // If legacy store exists, copy it to the new location
    NSFileManager* fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:legacyPersistentStoreURL.path])
    {
        NSError* thisError = nil;
        [fileManager copyItemAtURL:legacyPersistentStoreURL toURL:storeURL error:&thisError];
        [fileManager removeItemAtURL:legacyPersistentStoreURL error:&thisError];
    }

    return [super configurePersistentStoreCoordinatorForURL:storeURL ofType:fileType modelConfiguration:configuration storeOptions:storeOptions error:error];
}
like image 1
montuno Avatar answered Nov 14 '22 09:11

montuno