将iCloud数据迁移到本地存储,并停止iCloud仍然响应 [英] Migrate iCloud data to Local store and stopping iCloud from still responding

查看:201
本文介绍了将iCloud数据迁移到本地存储,并停止iCloud仍然响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很接近在我的应用程序中完成iCloud和Core Data的实现。这是一个仅限iOS 7的应用程序。



我在应用程序中向用户提供一个选项,表示以 UISwitch 。应用程序开始,并询问用户是否要使用iCloud,然后可以在应用程序中更改。



我有从本地存储(如果存在)迁移到iCloud的数据。我遇到的一个方面是将数据从iCloud Store迁移到本地存储。



场景:
- 用户A拥有包含我的应用程序和某些数据的iPhone
- 用户A将应用程序下载到iPad上, iCloud,但随后在稍后的时间,决定他们不想在iPad上同步。所以他们关闭了iPad iCloud在应用程序内同步。



此时,我的理解是,用户希望数据仍然存在,但从后台,它现在是LOCAL,而不是iCloud的数据,这意味着,其他设备的条目将不会同步到此设备,反之亦然



所以我想实现。


$ b

发出



我可以将数据从iCloud迁移到本地存储,但问题是,因为iCloud仍然在设备上启用,下次运行应用程序,我可以看到iCloud在应用程序中禁用,但控制台仍然显示使用本地存储1,然后0和任何数据从iPhone同步到iPad,即使使用iCloud UISwitch 非常清楚。



这是执行迁移的主要代码:

   - )migrateiCloudStoreToLocalStore {

NSLog(@Migrate iCloudToLocalStore);
NSPersistentStore * store = self.persistentStoreCoordinator.persistentStores.lastObject;

// NSURL * storeURL = [[self applicationDocumentsDirectory] ​​URLByAppendingPathComponent:@Envylope.sqlite];
NSURL * storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL];
NSLog(@当前商店URL(iCloud到本地迁移之前):%@,[storeURL description]);

NSDictionary * localStoreOptions = nil;
localStoreOptions = @ {NSPersistentStoreRemoveUbiquitousMetadataOption:@YES,
NSMigratePersistentStoresAutomaticallyOption:@YES,
NSInferMappingModelAutomaticallyOption:@YES};

NSPersistentStore * newStore = [self.persistentStoreCoordinator migratePersistentStore:store
toURL:storeURL
options:localStoreOptions
withType:NSSQLiteStoreType error:nil];

[self reloadStore:newStore];
}

- (void)reloadStore:(NSPersistentStore *)store {
NSLog(@Reload Store);
NSURL * storeURL = [[self applicationDocumentsDirectory] ​​URLByAppendingPathComponent:@Envylope.sqlite];
NSDictionary * localStoreOptions = nil;
localStoreOptions = @ {NSPersistentStoreRemoveUbiquitousMetadataOption:@YES,
NSMigratePersistentStoresAutomaticallyOption:@YES,
NSInferMappingModelAutomaticallyOption:@YES};

if(store){
[self.persistentStoreCoordinator removePersistentStore:store error:nil];
}

[self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:localStoreOptions
error:nil];
storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL];
NSLog(@当前商店URL(iCloud到本地迁移后):%@,[storeURL description]);

NSLog(@完成重新载入);

[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@MigratedFromiCloudToLocal];
[[NSUserDefaults standardUserDefaults] synchronize];

}

当然,有一些冗余代码, code> NSLog 之前的iCloud到本地迁移显示:

 当前商店网址iCloud到本地迁移):file:/// var / mobile / Applications / 62CAFCEE-450E-410D-9D56-4918DD70EC07 / Documents / CoreDataUbiquitySupport / mobile〜98457667-A467-4095-BB7F-EF36EB2B0FE1 / EnvyCloud / CD08912E-C135-4056 -9557-6B47C84ECEF9 / store / Envylope.sqlite 

数据迁移后的NSLog显示:

 当前商店URL(iCloud到本地迁移后):file:/// var / mobile / Applications / 62CAFCEE- 410D-9D56-4918DD70EC07 / Documents / Envylope.sqlite 

这清楚地显示数据已迁移到本地商店。但是,在控制台的这一点上,我不知道预期什么,但理想情况下,此过程应该有相同的效果,因为没有在设备上启用iCloud(如果我删除我的应用程序,删除我的iCloud帐户在设备上运行应用程序,我得到预期 - 运行应用程序无任何iCloud选项)。这不是发生,因为它继续推进iCloud更新。如果不再次运行该应用,则在其他设备中添加的数据会在此处同步。再次运行应用程序,使用本地存储1和0出现在控制台中。



因此,数据可能已迁移到本地存储,但在应用程序中禁用iCloud似乎没有效果。



我真的很感激对此的一些想法。



更新:以下两个答案的组合已找到解决方案。对于关注此问题的任何人,请查看以下问题:

这是一个两个步骤的过程:像@wottle建议,从你的应用程序中删除所有三个观察者。在iCloud数据迁移到新的本地商店文件后执行此操作:

   - (void)removeCloudObservers {

[[NSNotificationCenter defaultCenter] removeObserver:self name:NSPersistentStoreCoordinatorStoresWillChangeNotification object:self.managedObjectContext.persistentStoreCoordinator];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSPersistentStoreCoordinatorStoresDidChangeNotification object:self.managedObjectContext.persistentStoreCoordinator];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:self.managedObjectContext.persistentStoreCoordinator];
}

接下来,如果你确定要删除整个无处不在容器从iCloud(如我们手动之前),你可以在NSPersistentStoreCoordinator类(removeUbiquitousContentAndPersistentStoreAtURL)上调用一个singleton方法。获取有问题的iCloud存储文件(我将称为yourStore),然后使用如下所示:

   - (void) removeCloudContainer:(NSPersistentStore *)yourStore {

NSError * error = nil;
if(![NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:yourStore.URL options:yourStore.options错误:&错误]){
NSLog(@这没有那么好,这里是为什么:%@ ,error.localizedFailureReason);
}
}

这将删除整个容器,将能够访问iCloud数据了。执行此操作一旦iCloud存储从协调器中删除,并且应用程序已经在本地存储上已经运行愉快。



从UI的角度来看,它可能是一个好主意让用户在所有设备上的所有数据都迁移到本地存储,而不是将其集成到切换iCloud关闭例程之后做出此选择 - 只是因为它可能很难处理仍然期望iCloud存储在那里。


I am so close to completing the implementation of iCloud and Core Data in my app. This is an iOS 7 only app.

I am providing the user with an option within the app to say Use iCloud On or Off in the form of a UISwitch. The app starts out and asks the user if they want to use iCloud or not and this can then later be changed within the app.

I have the data migrating from the local store (if it exists) to iCloud. The one aspect I'm struggling with is migrating the data from the iCloud Store to the Local store.

Scenario: - User A has an iPhone with my app and some data - User A downloads the app onto the iPad, selects to use iCloud but then at a later point, decides they do not want synching on the iPad. So they turn off the iPad iCloud synching within the app.

At this point, my understanding is that a user would expect the data to still be there, but from behind the scenes, it's now "LOCAL" instead of "iCloud" based data which means, entries from the other device won't synchronise over to this device and vice versa

So I am trying to achieve that.

Issue

I can get the data to migrate from the iCloud to the local store, but the issue is that because iCloud is still enabled on the device, the next time the app is run, I can see that iCloud is disabled within the app but the console still shows Using Local Storage 1 and then 0 and any data from the iPhone synchronises across to the iPad, even though the Use iCloud UISwitch is very clearly off.

Here's the main code doing the migration:

- (void)migrateiCloudStoreToLocalStore {

    NSLog(@"Migrate iCloudToLocalStore");
    NSPersistentStore *store = self.persistentStoreCoordinator.persistentStores.lastObject;

    //NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Envylope.sqlite"];
    NSURL *storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL];
    NSLog(@"Current Store URL (before iCloud to Local migration): %@", [storeURL description]);

    NSDictionary *localStoreOptions = nil;
    localStoreOptions = @{ NSPersistentStoreRemoveUbiquitousMetadataOption : @YES,
                           NSMigratePersistentStoresAutomaticallyOption : @YES,
                           NSInferMappingModelAutomaticallyOption : @YES};

    NSPersistentStore *newStore = [self.persistentStoreCoordinator migratePersistentStore:store
                                                                                     toURL:storeURL
                                                                                   options:localStoreOptions
                                                                                  withType:NSSQLiteStoreType error:nil];

    [self reloadStore:newStore];
}

- (void)reloadStore:(NSPersistentStore *)store {
    NSLog(@"Reload Store");        
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Envylope.sqlite"];
    NSDictionary *localStoreOptions = nil;
    localStoreOptions = @{ NSPersistentStoreRemoveUbiquitousMetadataOption : @YES,
                           NSMigratePersistentStoresAutomaticallyOption : @YES,
                           NSInferMappingModelAutomaticallyOption : @YES};

    if (store) {
        [self.persistentStoreCoordinator removePersistentStore:store error:nil];
    }

    [self.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
                                                  configuration:nil
                                                            URL:storeURL
                                                        options:localStoreOptions
                                                          error:nil];
    storeURL = [self.persistentStoreCoordinator.persistentStores.lastObject URL];
    NSLog(@"Current Store URL (after iCloud to Local migration): %@", [storeURL description]);

    NSLog(@"Done reloading");

    [[NSUserDefaults standardUserDefaults]setBool:YES forKey:@"MigratedFromiCloudToLocal"];
    [[NSUserDefaults standardUserDefaults]synchronize];

}

Sure, there's some redundant code in there, but the NSLog for before iCloud to Local Migration shows:

 Current Store URL (before iCloud to Local migration): file:///var/mobile/Applications/62CAFCEE-450E-410D-9D56-4918DD70EC07/Documents/CoreDataUbiquitySupport/mobile~98457667-A467-4095-BB7F-EF36EB2B0FE1/EnvyCloud/CD08912E-C135-4056-9557-6B47C84ECEF9/store/Envylope.sqlite

The NSLog for after the data has been migrated shows:

Current Store URL (after iCloud to Local migration): file:///var/mobile/Applications/62CAFCEE-450E-410D-9D56-4918DD70EC07/Documents/Envylope.sqlite

This clearly shows the data has been migrated over to the local store. However, at this point in the console, I'm not sure what to expect, but ideally, this procedure should have the same effect as there not being iCloud enabled on the device at all (if I delete my app, delete my iCloud account on the device and run the app, I get the expected - run the app WITHOUT any iCloud options). This is not happening because it continues to push forward iCloud updates. Without running the app again, data added in the other device syncs across here. With running the app again, the using local storage 1 and 0 appear in the console.

Therefore, the data may have been migrated to a local store, but disabling iCloud within the app seems to have no effect.

I would really appreciate some thoughts on this.

Update: The solution has been found as a combination of both answers below. For anyone following this question to see the next scenario, please refer to this question: Migrating an iCloud Store to a Local Store and making sure the data is there through each app launch

解决方案

It's a two-step process: like @wottle suggests, remove all three observers from your app. Do this once the iCloud data has been migrated to a new local store file:

- (void)removeCloudObservers {

[[NSNotificationCenter defaultCenter]removeObserver:self name:NSPersistentStoreCoordinatorStoresWillChangeNotification object:self.managedObjectContext.persistentStoreCoordinator];
[[NSNotificationCenter defaultCenter]removeObserver:self name:NSPersistentStoreCoordinatorStoresDidChangeNotification object:self.managedObjectContext.persistentStoreCoordinator];
[[NSNotificationCenter defaultCenter]removeObserver:self name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:self.managedObjectContext.persistentStoreCoordinator];
}

Next, if you're absolutely positive that you want to remove the entire ubiquitous container from iCloud (as we did manually before), you can call a singleton method on the NSPersistentStoreCoordinator class (removeUbiquitousContentAndPersistentStoreAtURL). Grab the iCloud store file in question (I'll call it yourStore) and then use something like this:

- (void)removeCloudContainer:(NSPersistentStore *)yourStore {

NSError *error = nil;
if (![NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:yourStore.URL options:yourStore.options error:&error]) {
    NSLog(@"That didn't work so well, and here's why: %@", error.localizedFailureReason);
}
}

This will remove the entire container, and no other devices will be able to access iCloud data anymore. Do this once the iCloud store is removed from the coordinator and when the app is already running happily on the local store.

From a UI point of view, it may be a good idea to let users make this choice after all data on all devices has been migrated to local stores rather than integrate this into the "switch iCloud off" routine - only because it may be tricky to deal with peers that still expect an iCloud store to be there.

这篇关于将iCloud数据迁移到本地存储,并停止iCloud仍然响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆