简体   繁体   English

如何将初始数据播种到Core Data + iCloud?

[英]How to seed initial data to Core Data + iCloud?

I'm working on a new app that uses Core Data and iCloud. 我正在开发一个使用Core Data和iCloud的新应用。 I'm following the iCloudCoreDataStack demo and the iCloud Design Guide. 我正在关注iCloudCoreDataStack演示和iCloud设计指南。 So far the synchronization between devices is working well, but I haven't figured out how to seed a small amount of data the first time the app is used on the user's first device and skip the seeding if the app is used on a second device (since it should download from iCloud instead). 到目前为止,设备之间的同步运行良好,但我还没有弄清楚如何在用户的第一台设备上使用应用程序时播种少量数据,如果应用程序在第二台设备上使用,则跳过播种(因为它应该从iCloud下载)。

This should be easy, just ask the iCloud Container if it has any data. 这应该很简单,只要询问iCloud Container是否有任何数据。 Download the data if it exists or create new data if it doesn't. 下载数据(如果存在)或创建新数据(如果不存在)。 But I couldn't find a way to do this :-( 但我找不到办法做到这一点:-(

I can think of three ways to solve this: 我可以想到三种方法来解决这个问题:

  1. Use migratePersistentStore:toURL:options:withType:error: I have a very small amount of data, so for this case this feels like overkill 使用migratePersistentStore:toURL:options:withType:error:我的数据量非常少,所以对于这种情况,这感觉就像是矫枉过正

  2. Store a value on NSUbiquitousKeyValueStore to mark if the initial synchronization has been made I tried using NSUbiquitousKeyValueStore, but sometimes it would take too long to get the value from the UbiquitousKeyValueStore, so the seed data would be created even when not needed, resulting in duplicates. 在NSUbiquitousKeyValueStore上存储一个值以标记是否已经进行了初始同步我尝试使用NSUbiquitousKeyValueStore,但有时从UbiquitousKeyValueStore获取值需要很长时间,因此即使在不需要时也会创建种子数据,从而导致重复。

  3. Use a sentinel file to have the same effect of #2 (I'm not sure how to implement this) 使用sentinel文件与#2具有相同的效果(我不知道如何实现这个)

The App is iOS 7 only and new, so there's no need to migrate old user data. 该应用程序仅适用于iOS 7和新版本,因此无需迁移旧用户数据。

Every relevant tutorial and book that I found seemed to be using the pre-iOS7 super complex way of doing things (eg using a fallback store) that is not necessary on iOS 7. 我发现的每个相关教程和书籍似乎都使用iOS7之前的超级复杂的处理方式(例如使用后备存储),这在iOS 7中是不必要的。

Either I'm missing something (often the case) or this is more complicated than it should be. 要么我缺少某些东西(通常是这种情况),要么这比它应该更复杂。 I appreciate any suggestions and pointers. 我感谢任何建议和指示。

It is never a good idea to seed a distributed datastore with an initial dataset. 使用初始数据集为分布式数据存储区播种永远不是一个好主意。 Generally this initial data can be packaged into a store file that is shipped with the application, and added as a second persistent store to the coordinator used by your application's managed object context. 通常,这些初始数据可以打包到随应用程序一起提供的存储文件中,并作为第二个持久存储添加到应用程序的托管对象上下文使用的协调器中。

That said, it is possible, although unwise to seed based on the completion of Core Data's initial import. 也就是说,基于Core Data初始导入的完成,种子虽然不明智是可能的。

You need to wait for NSPersistentStoreCoordinatorStoresDidChangeNotification with NSPersistentStoreUbiquitousTransitionTypeKey set to NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted . 您需要等待NSPersistentStoreCoordinatorStoresDidChangeNotification, 并将NSPersistentStoreUbiquitousTransitionTypeKey设置为NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted

If there is no data in the store you can seed your initial data set at that point. 如果商店中没有数据,您可以在该点播种初始数据集。

However it is important to realize that multiple devices could receive the initial import notification without importing the seeded data and thus seed it again. 但是,重要的是要意识到多个设备可以在不导入种子数据的情况下接收初始导入通知,从而再次播种。 There is no way to avoid this. 没有办法避免这种情况。


On the point of shipping a second persistent store with your application, to serve as seed data. 关于使用您的应用程序发送第二个持久性存储的问题,用作种子数据。

This is accomplished as Marcus points out below by adding it as a read only store to the persistent store coordinator that is in use by your app's managed object context. 这是在Marcus通过将其作为只读存储添加到应用程序的托管对象上下文正在使用的持久性存储协调器时指出的。

NSDictionary *options = @{ NSReadOnlyPersistentStoreOption: @YES };
[_psc addPersistentStoreWithType:NSSQLiteStoreType
                   configuration:nil
                             URL:seedStoreURL
                         options:options
                           error:&localError];

NSDictionary *iCloudOptions = @{ NSPersistentStoreUbiquitousContentNameKey: @"storeName" };
[_psc addPersistentStoreWithType:NSSQLiteStoreType
                   configuration:nil
                             URL:iCloudStoreURL
                         options:iCloudOptions
                           error:&localError];

_moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[appMOC setPersistentStoreCoordinator:_psc];

This way your application's managed object context has access to data from both stores and will fetch both sets from fetch requests. 这样,应用程序的托管对象上下文可以访问两个存储中的数据,并从获取请求中获取这两个集。 The managed object context is also smart enough to automatically insert new objects into the correct store (because one of them is read only). 托管对象上下文也足够智能,可以自动将新对象插入到正确的存储中(因为其中一个是只读的)。

The only trick is that if you want your user to be able to modify data from the seed store you'll need to move those objects to the iCloud store. 唯一的技巧是,如果您希望用户能够从种子库修改数据,则需要将这些对象移动到iCloud存储。

This is a much easier approach than trying to migrate the dataset wholesale because ideally your user will only be using a single device at a time. 这比尝试迁移批量数据集更容易,因为理想情况下,您的用户一次只能使用单个设备。 In the case of a collision you'll at most have to resolve a few duplicate records as opposed to trying to detect duplication across the entire dataset. 在发生冲突的情况下,您最多必须解决一些重复记录,而不是尝试检测整个数据集中的重复。

Try this approach: 试试这种方法:

Before creating the local store check if one has already been created in iCloud by looking for the presence of a directory with the 'NSPersistentStoreUbiquitousNameKey' name in the iCloud /CoreData directory. 在创建本地存储之前,通过在iCloud / CoreData目录中查找存在具有“NSPersistentStoreUbiquitousNameKey”名称的目录,检查是否已在iCloud中创建了一个。

If one exists then this means that some other device has already created a store and shared it in iCloud so when creating your local store on the device don't add seed data because this will already exist in iCloud. 如果存在,那么这意味着其他设备已经创建了一个商店并在iCloud中共享它,因此在设备上创建本地商店时不会添加种子数据,因为这已经存在于iCloud中。

If one does not exist then no other device has shared the store in iCloud yet so you can probably create your seed data and sync to iCloud. 如果其中一个不存在,则其他设备尚未在iCloud中共享该存储,因此您可以创建种子数据并同步到iCloud。

NOTE that the following scenarios are not catered for: 请注意,以下方案不适用于:

  • A user is running the app on a device that does not have iCloud enabled - if the user chooses to now sync with iCloud from this device you will have to deal with issues arising from trying to merge data from this device with data already in iCloud. 用户正在未启用iCloud的设备上运行应用程序 - 如果用户现在选择从此设备与iCloud同步,则必须处理尝试将此设备中的数据与iCloud中已有数据合并而产生的问题。 Once again you can check for the presence of data in iCloud and then ask the user whether they want to try merging data from the device or whether they want to replace the data with data from iCloud. 您可以再次检查iCloud中是否存在数据,然后询问用户是否要尝试合并设备中的数据,或者是否要将数据替换为来自iCloud的数据。

  • A user is running the app on a device that is not connected to the network - and has not had any data synced from iCloud yet so thinks there is no file already in iCloud. 用户正在未连接到网络的设备上运行应用程序 - 并且尚未从iCloud同步任何数据,因此认为iCloud中已存在任何文件。 The app will then create seed data and when it gets a network connection Core Data will merge the data - you app may have to deal with the ensuing problems. 然后,应用程序将创建种子数据,当它获得网络连接时,Core Data将合并数据 - 您的应用程序可能必须处理随后出现的问题。

For these scenario's you may need to try user education. 对于这些场景,您可能需要尝试用户培训。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM