Automatic lightweight migration works for local storage but iCloud storage "loses" all legacy data
Asked Answered
M

0

7

I'm tearing my hair out with this one. I've got an App on iTunes which I added iCloud support to end of last year (Oct '13) on iOS7.0 This week I decided to write a new functional for the App which requires a new entity in the xcdatamodel. A very simple change/addition. Should have no impact on the current data set. I create a new v2 xcdatamodel and set it to Current Model version, compile and run and it works fine if I've got iCloud switch off on my iPad. I see previous saved data. Run it again with iCloud switch on and I get a blank table with no data. No error messages, nothing. Hoping someone can throw some light on what I've done wrong here:

 - (NSManagedObjectModel *)managedObjectModel {
    if (__managedObjectModel != nil) {
        return __managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"UserData" withExtension:@"momd"];
    __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return __managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    NSError *error = nil;
    BOOL success = NO;

    if((__persistentStoreCoordinator != nil)) {
        return __persistentStoreCoordinator;
    }

    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
    NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator;

    NSString *iCloudEnabledAppID = @"C3FUPX46ZG~com~software~App";
    NSString *dataFileName = @"UserData.sqlite";
    NSString *iCloudDataDirectoryName = @"CoreData.nosync";
    NSString *iCloudLogsDirectoryName = @"CoreDataLogs";
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
    NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];

    if (iCloud && ([UserDefaults getIsiCloudOn])) {
        // This iCloud storage fails to migrate.
        NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];

        if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
            NSError *fileSystemError;
            [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
                   withIntermediateDirectories:YES
                                    attributes:nil
                                         error:&fileSystemError];
            if(fileSystemError != nil) {
                NSLog(@"Error creating database directory %@", fileSystemError);
            }
        }

        NSString *iCloudData = [[[iCloud path]
                                 stringByAppendingPathComponent:iCloudDataDirectoryName]
                                stringByAppendingPathComponent:dataFileName];

        NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption : @YES,
                                  NSInferMappingModelAutomaticallyOption : @YES,
                                  NSPersistentStoreUbiquitousContentNameKey : iCloudEnabledAppID,
                                  NSPersistentStoreUbiquitousContentURLKey : iCloudLogsPath
                                  };

        success = [psc addPersistentStoreWithType:NSSQLiteStoreType
                                    configuration:nil
                                              URL:[NSURL fileURLWithPath:iCloudData]
                                          options:options
                                            error:&error];

        if (!success) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        }
    } else {
        // This local storage migrates automatically just fine.
        NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption : @YES,
                                  NSInferMappingModelAutomaticallyOption : @YES
                                  };

        success = [psc addPersistentStoreWithType:NSSQLiteStoreType
                                    configuration:nil
                                              URL:localStore
                                          options:options
                                            error:&error];

        if (!success) {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        }
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:kCoreDataChangeNotification object:self userInfo:nil];
    });

    return __persistentStoreCoordinator;
}

UPDATE: Switched on core data debugging & iCloud debugging/logging. Migration works for both local & iCloud. Logs are the same, ending with:

CoreData: annotation: (migration) inferring a mapping model between data models with... CoreData: annotation: (migration) in-place migration completed succeessfully in 0.03 seconds -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: mobile~F9AC6EB1 Using local storage: 1

With iCloud storage & debugging on it seems to cause a delay and I briefly see my saved data for about 10seconds when it then disappears. Just before it disappears the debugs spit out:

CoreData: annotation: (migration) inferring a mapping model between data models with... Using local storage: 0

The iCloud logs are enormous which is why I'm not posting them here. From what I can see I have over 400 log files and iCloud seems to be doing some sort of syncing. If I leave the App and iPad open and on for a few hours I still see an empty data set. So it's not a case of waiting for a sync catch up. I'm still at a loss even with the debugs on....

Mahau answered 4/7, 2014 at 10:7 Comment(7)
What happens when you turn on Core Data and iCloud debugging messages?Imperator
I seem to recall this is expected behavior. I think the data reappears when the device has the newest model. There can also be a delay while core data brings everything back up to date. It might be that it reverts to the fallback store for a bit, so make sure you monitor the notifications.Wedgwood
In frustration I ripped out the use of CoreData for this new feature and just used my own sqlite implementation to store this new table I need. Then I discovered, in releasing an Ad-Hoc beta image for someone, that the current iCloud saved data disappears when you load the Ad-Hoc image. I'm now wondering if the root of the problem is iCloud not using the same data space for dev & ad-hoc(beta) images?Mahau
Have you figured out a solution to this?Doe
developer.apple.com/library/ios/qa/qa1883/_index.htmlScandent
@Mahau does the link above answer to your question about data space? I'm having the same problem and this is killing meScandent
@Scandent Sorry, I gave up in the end and left out iCloud syncing for the feature I added. I may re-visit it once Apple has revised and it's matured a bit more. I get the impression it's still buggy and early days.Mahau

© 2022 - 2024 — McMap. All rights reserved.