Xcode 6 iOS 8 iCloud核心数据设置

有没有人在Xcode 6和iOS 8上有iCloud核心数据同步设置? (希望这不是一个重复的职位)

iCloud核心数据存储选项去了哪里?

我记得Core Data有一个额外的存储选项,称为核心数据存储,但现在在Xcode 6中,似乎只有在启用Xcode 6中的iCloud切换时才显示键值和文档存储。

背景信息

  • 新的iPad应用程序
  • Xcode 6
  • 针对最低版本的iOS 7,但希望它也适用于iOS 8? (我们可以将iOS 8设置为最低)
  • 想要使用iCloud Core Data存储,而不是键值或文档存储。
  • 已经在设置> iCloud中为Simulator和iPad设备login了相同的Apple帐户
  • 我的configuration文件用于代码签署应用程序启用了iCloud的开发和分配(由Xcode自动启用)

我的设置

到目前为止,我不知道我是否正确设置了Core Data iCloud。

Xcode似乎已经在iOS Developer Portal中设置了iCloud容器:

iCloud.com.xxxxxx.xxxxxxxx (note: I've replaced the actual strings with xxxx here) 

我的Xcode 6 iCloud“服务”列表显示旁边没有刻度:

  • 键值存储
  • iCloud文档
  • CloudKit

我们现在应该使用哪一个,因为它没有列出“核心数据”作为存储选项?

在“服务”正下方的“容器”中,它显示以下灰色的选项:

  • 使用默认容器(默认情况下打勾)
  • 指定自定义容器
  • iCloud.com.xxxxxxxxxx.xxxxxxxxx(再次用xxxxreplace真实标识符)

我不能select任何选项,似乎迫使我“使用默认容器”。

最后,Xcode似乎显示为:

  • 将“iCloud”权利添加到您的应用程序ID
  • 将“iCloud容器”权利添加到您的应用程序ID
  • 将“iCloud”授权添加到您的授权文件中
  • 链接CloudKit.framework

所以通过Xcode自己的自动化过程,它为我设置了一切。

参考代码

好的,所以我四处阅读,注意到这里写了一个iCloud堆栈:

https://github.com/mluisbrown/iCloudCoreDataStack

我已经采取了必要的代码,并尝试适应我的核心数据pipe理器单身人士:

DataManager.h文件

 + (id)sharedModel; + (ALAssetsLibrary *)sharedLibrary; @property (nonatomic, readonly) NSManagedObjectContext *mainContext; @property (nonatomic, readonly) NSPersistentStoreCoordinator *storeCoordinator; - (NSString *)modelName; - (NSString *)pathToModel; - (NSString *)storeFilename; - (NSString *)pathToLocalStore; #pragma mark - Entity Fetching Methods - -(NSArray *)fetchEntityOfType:(NSString *)entityType UsingPredicated:(NSPredicate *)predicate sortBy:(NSString *)sortKey ascendingOrder:(BOOL)ascendingOrder; 

DataManager.m文件

 @property (nonatomic, strong) NSManagedObjectModel *managedObjectModel; - (NSString *)documentsDirectory; @end @implementation MLSAlbumsDataModel @synthesize managedObjectModel = _managedObjectModel; @synthesize storeCoordinator = _storeCoordinator; @synthesize mainContext = _mainContext; + (id)sharedModel { static MLSAlbumsDataModel *__instance = nil; if (__instance == nil) { __instance = [[MLSAlbumsDataModel alloc] init]; } return __instance; } + (ALAssetsLibrary *)sharedLibrary { static ALAssetsLibrary *__instance = nil; if (__instance == nil) { __instance = [[ALAssetsLibrary alloc] init]; } return __instance; } - (NSString *)modelName { return @"Albums"; } - (NSString *)pathToModel { return [[NSBundle mainBundle] pathForResource:[self modelName] ofType:@"momd"]; } - (NSString *)storeFilename { return [[self modelName] stringByAppendingPathExtension:@"sqlite"]; } - (NSString *)pathToLocalStore { return [[self documentsDirectory] stringByAppendingPathComponent:[self storeFilename]]; } - (NSString *)documentsDirectory { NSString *documentsDirectory = nil; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); documentsDirectory = [paths objectAtIndex:0]; return documentsDirectory; } - (NSManagedObjectContext *)mainContext { if(_mainContext == nil) { _mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; _mainContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; // setup persistent store coordinator DLog(@"SQLITE STORE PATH: %@", [self pathToLocalStore]); NSURL *storeURL = [NSURL fileURLWithPath:[self pathToLocalStore]]; //_mainContext.persistentStoreCoordinator = [self storeCoordinator]; _mainContext.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; __weak NSPersistentStoreCoordinator *psc = self.mainContext.persistentStoreCoordinator; // iCloud notification subscriptions NSNotificationCenter *dc = [NSNotificationCenter defaultCenter]; [dc addObserver:self selector:@selector(storesWillChange:) name:NSPersistentStoreCoordinatorStoresWillChangeNotification object:psc]; [dc addObserver:self selector:@selector(storesDidChange:) name:NSPersistentStoreCoordinatorStoresDidChangeNotification object:psc]; [dc addObserver:self selector:@selector(persistentStoreDidImportUbiquitousContentChanges:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:psc]; NSError* error; // the only difference in this call that makes the store an iCloud enabled store // is the NSPersistentStoreUbiquitousContentNameKey in options. I use "iCloudStore" // but you can use what you like. For a non-iCloud enabled store, I pass "nil" for options. // Note that the store URL is the same regardless of whether you're using iCloud or not. // If you create a non-iCloud enabled store, it will be created in the App's Documents directory. // An iCloud enabled store will be created below a directory called CoreDataUbiquitySupport // in your App's Documents directory [self.mainContext.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:@{ NSPersistentStoreUbiquitousContentNameKey : @"iCloudStore" } error:&error]; if (error) { NSLog(@"error: %@", error); } _storeCoordinator = self.mainContext.persistentStoreCoordinator; } return _mainContext; } - (NSManagedObjectModel *)managedObjectModel { if(_managedObjectModel == nil) { NSURL *storeURL = [NSURL fileURLWithPath:[self pathToModel]]; _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:storeURL]; } return _managedObjectModel; } - (NSPersistentStoreCoordinator *)storeCoordinator { if (_storeCoordinator == nil) { // ----------------------------------------------------------------------------------------------------------------------------- // Code moved to managed object context code above // ----------------------------------------------------------------------------------------------------------------------------- /* DLog(@"SQLITE STORE PATH: %@", [self pathToLocalStore]); NSURL *storeURL = [NSURL fileURLWithPath:[self pathToLocalStore]]; NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; NSError *error = nil; if (![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) { NSDictionary *userInfo = [NSDictionary dictionaryWithObject:error forKey:NSUnderlyingErrorKey]; NSString *reason = @"Could not create persistent store"; NSException *exc = [NSException exceptionWithName:NSInternalInconsistencyException reason:reason userInfo:userInfo]; @throw exc; } _storeCoordinator = psc; */ } return _storeCoordinator; } #pragma mark - iCloud Related Methods - // Subscribe to NSPersistentStoreDidImportUbiquitousContentChangesNotification - (void)persistentStoreDidImportUbiquitousContentChanges:(NSNotification*)note { NSLog(@"%s", __PRETTY_FUNCTION__); NSLog(@"%@", note.userInfo.description); NSManagedObjectContext *moc = self.mainContext; [moc performBlock:^{ [moc mergeChangesFromContextDidSaveNotification:note]; DLog(@"NSPersistentStoreDidImportUbiquitousContentChangesNotification executed"); /* // you may want to post a notification here so that which ever part of your app // needs to can react appropriately to what was merged. // An exmaple of how to iterate over what was merged follows, although I wouldn't // recommend doing it here. Better handle it in a delegate or use notifications. // Note that the notification contains NSManagedObjectIDs // and not NSManagedObjects. NSDictionary *changes = note.userInfo; NSMutableSet *allChanges = [NSMutableSet new]; [allChanges unionSet:changes[NSInsertedObjectsKey]]; [allChanges unionSet:changes[NSUpdatedObjectsKey]]; [allChanges unionSet:changes[NSDeletedObjectsKey]]; for (NSManagedObjectID *objID in allChanges) { // do whatever you need to with the NSManagedObjectID // you can retrieve the object from with [moc objectWithID:objID] } */ }]; } // Subscribe to NSPersistentStoreCoordinatorStoresWillChangeNotification // most likely to be called if the user enables / disables iCloud // (either globally, or just for your app) or if the user changes // iCloud accounts. - (void)storesWillChange:(NSNotification *)note { NSManagedObjectContext *moc = self.mainContext; [moc performBlockAndWait:^{ NSError *error = nil; if ([moc hasChanges]) { [moc save:&error]; } [moc reset]; }]; // now reset your UI to be prepared for a totally different // set of data (eg, popToRootViewControllerAnimated:) // but don't load any new data yet. [[NSNotificationCenter defaultCenter] postNotificationName:@"notifCoreDataStoreWillChange" object:nil]; DLog(@"storeWillChange notification fire"); } // Subscribe to NSPersistentStoreCoordinatorStoresDidChangeNotification - (void)storesDidChange:(NSNotification *)note { // here is when you can refresh your UI and // load new data from the new store [[NSNotificationCenter defaultCenter] postNotificationName:@"notifCoreDataStoreDidChange" object:nil]; DLog(@"storeDidChange notification fire"); } #pragma mark - Entity Fetching Methods - -(NSArray *)fetchEntityOfType:(NSString *)entityType UsingPredicated:(NSPredicate *)predicate sortBy:(NSString *)sortKey ascendingOrder:(BOOL)ascendingOrder { NSEntityDescription *entityDescription = [NSEntityDescription entityForName:entityType inManagedObjectContext:[[MLSAlbumsDataModel sharedModel] mainContext]]; NSSortDescriptor *sortDescriptor = nil; if(sortKey) { sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:ascendingOrder]; } else { sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"updatedAt" ascending:ascendingOrder]; } NSFetchRequest *request = [[NSFetchRequest alloc] init]; request.entity = entityDescription; if(predicate) { request.predicate = predicate; } request.sortDescriptors = @[sortDescriptor]; NSError *error = nil; NSArray *results = [[[MLSAlbumsDataModel sharedModel] mainContext] executeFetchRequest:request error:&error]; if(results == nil) { DLog(@"Error getting entity of type '%@' using predicate '%@', sortKey '%@' ascendingOrder %d", entityType, predicate, sortKey, ascendingOrder); } return results; } 

我的观察

我试图在iPad模拟器(我相信这是iOS 8模拟器)和运行iOS 7.x的iPad设备上运行应用程序

我在模拟器上创build了一个用户input名字的相册,但是我没有看到iPad设备显示新创build的相册。 我也试过扭转angular色,iPad设备创build,iOS模拟器也没有结果。

我看到我的日志消息:

 storeDidChange notification fire SQLITE STORE PATH: /Users/xxxxxxx/Library/Developer/CoreSimulator/Devices/3DC17576-92E9-4EAF-B77A-41340AE28F92/data/Containers/Data/Application/E51085CE-3772-4DF1-A503-1C243497091A/Documents/Albums.sqlite 

如果我最小化模拟器中的应用程序并再次打开(不按Xcode中的停止button),我看到这些消息:

 -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](808): CoreData: Ubiquity: nobody~sim301AE3E8-16B2-5A08-917D-7B55D1879BE4:iCloudStore Using local storage: 1 

我读到“使用本地存储:0”是理想的应该是什么? 而1表示本地设备数据存储而不是iCloud数据存储。

当我创build一个专辑,保存它,停止模拟器,然后再次启动应用程序,我的专辑消失,但创build一个新的专辑后,所有以前的专辑再次神奇再次出现。 这有点奇怪 如果我不使用iCloud并将代码恢复到以前的设置,则无论是否将我的应用程序最小化或重新启动应用程序,我都可以创build并查看我的相册,但是之后我没有iCloud同步。

我在任何地方犯了什么错误吗?

对不起,很长的职位,但任何人都有iCloud iOS 8和Xcode 6的工作?

我真的可以使用一些帮助。

额外的问题

1)iOS 8是否需要使用这个容器标识符? (Xcode 6为我生成的):

 com.apple.developer.icloud-container-identifiers 

那不是iOS 7的样子吧? iOS 7更像是:

 com.apple.developer.ubiquity-container-identifiers 

2)我需要一个iCloud云端硬盘账号吗?

超级困惑@ _ @

iOS 8解决scheme:

OK …然后….大声笑。 我想我解决了它。

新的发现。 在浏览此页面之后:

http://www.tuaw.com/2014/09/17/psa-do-not-upgrade-to-icloud-drive-during-ios-8-installation/

它说:

iCloud Drive是苹果公司全新改进的iCloud同步和文件存储function,允许您在iOS 8设备和运行OS X 10 Yosemite的Mac之间共享文档。

所以,我决定硬着头皮将iCloud帐号升级到iCloud硬盘(免费升级)。

升级到iCloud驱动器后,重新运行我的应用程序几个Xcode 6的变化,现在工作。

一些重要的事情要注意:

  • iCloud Drive与以前的iCloud文档和数据存储不兼容。 所以,如果你要testing,确保所有的设备都使用iCloud驱动器和iOS 8。
  • 模拟器似乎只同步一次,启动应用程序后,设备连续同步每隔一段时间。 不知道这是否是一个模拟器错误。 或者,也许我的configuration不完美。
  • 使用“使用默认的容器”在我的模拟器中不起作用(但是在它的设备上它工作),可能需要删除以前的应用程序副本并重新安装。 先尝试使用默认的容器,看看它是否工作,否则,读下面的下一个点。
  • 由于上述原因,我改变了使用这种模式的Ubiquity容器:

    iCloud中。$(CFBundleIdentifier)

所以像这样:

 iCloud.com.xxxxxxxx.iCloudCoreDataDemo 

其中“xxxxxxxx”是我的公司名称标识符。

我通过login到我的iOS开发人员中心制作了上面的iCloud容器,也许你可以按Xcode 6里面的“+”号并input一个,Xcode应该自动为你设置一切。

我用来testing的代码块是否可以正常工作:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.persistentStack = [[PersistentStack alloc] initWithStoreURL:self.storeURL modelURL:self.modelURL]; self.managedObjectContext = self.persistentStack.managedObjectContext; NSURL *containerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:@"iCloud.com.xxxxxxxxxx.iCloudCoreDataDemo"]; if(containerURL == nil) { NSLog(@"containerURL == nil"); } else { NSLog(@"hurray?"); } return YES; } 

如果你看到“欢呼声”? 那么很好,你也应该在你的Xcode控制台输出中看到这种模式的文本:

 2014-10-07 17:37:23.196 iCloudCoreDataDemo[8104:130250] documentsDirectory = file:///Users/xxxxxxxx/Library/Developer/CoreSimulator/Devices/9FAFE881-13CA-4608-8BE6-728C793FAFFB/data/Containers/Data/Application/BC6CA07D-605A-4927-94AF-E9E21E204D2B/Documents/ 2014-10-07 17:37:23.386 iCloudCoreDataDemo[8104:130250] storeDidChange 2014-10-07 17:37:23.390 iCloudCoreDataDemo[8104:130250] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](808): CoreData: Ubiquity: nobody~sim301AE3E8-16B2-5A08-917D-7B55D1879BE4:iCloudStore Using local storage: 1 2014-10-07 17:37:23.402 iCloudCoreDataDemo[8104:130250] hurray? 2014-10-07 17:37:33.909 iCloudCoreDataDemo[8104:130250] storeWillChange 2014-10-07 17:37:33.933 iCloudCoreDataDemo[8104:130250] storeDidChange 2014-10-07 17:37:33.933 iCloudCoreDataDemo[8104:130330] -[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](808): CoreData: Ubiquity: nobody~sim301AE3E8-16B2-5A08-917D-7B55D1879BE4:iCloudStore Using local storage: 0 

注意两条重要的路线:

 Using local storage: 1 

以后变成:

 Using local storage: 0 

本地存储1表示当前正在使用本地存储,而本地存储0表示已将数据移至iCloud存储。

我希望这有利于其他人。

仅限iOS 7解决scheme:

好的,所以我刚刚发现了一些东西,并设法使其仅适用于iOS 7 。 我还没有想出如何在iOS 8中做到这一点,但我注意到了一些重要的东西。

在运行iOS 8.0.2的iPhone 5上,我没有iCloud设置菜单中的“ 文档和数据 ”选项。

但是,在运行iOS 7的iPad上,我可以看到“文档和数据”选项。

也许这就是为什么它不适用于iOS 8的原因,我们不再有文档和数据存储?

无论如何,这就是我发现的iOS 7解决scheme。

我在这里find了这个页面

https://developer.apple.com/library/ios/documentation/General/Conceptual/iCloudDesignGuide/Chapters/iCloudFundametals.html

其中一行说:

  • iCloud文档存储用于用户可见的基于文件的内容, 核心数据存储或用于其他复杂的基于文件的内容。

果然,我进入了我的Xcode 6项目文件并勾选了“iCloud Documents”选项。 这使得单选button变成灰色,但我仍然将它放在“使用默认容器”中。

我学到的一件事是我需要在appDelegate中初始化我的PersistentStack。 以前,我试图在+(id)sharedInstance方法中初始化持久堆栈,但是它导致iCloud只能第一次同步,所以在初始加载和同步之后,添加新logging之后不会同步。

我重写了一个基本的应用程序,并稍微修改了持久性堆栈:

App Delegate.h

 #import <UIKit/UIKit.h> #import "PersistentStack.h" @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (nonatomic, strong) NSManagedObjectContext* managedObjectContext; @property (nonatomic, strong) PersistentStack* persistentStack; @end 

App Delegate.m

 @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.persistentStack = [[PersistentStack alloc] initWithStoreURL:self.storeURL modelURL:self.modelURL]; self.managedObjectContext = self.persistentStack.managedObjectContext; return YES; } ... - (NSURL*)storeURL { NSURL* documentsDirectory = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL]; return [documentsDirectory URLByAppendingPathComponent:@"MyApp.sqlite"]; } - (NSURL*)modelURL { return [[NSBundle mainBundle] URLForResource:@"MyApp" withExtension:@"momd"]; } 

持久Stack.h

 #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> #import "Book.h" #import <UIKit/UIKit.h> @interface PersistentStack : NSObject +(id)sharedInstance; - (id)initWithStoreURL:(NSURL *)storeURL modelURL:(NSURL *)modelURL; @property (nonatomic,strong,readonly) NSManagedObjectContext *managedObjectContext; #pragma mark - Regular Methods - -(Book *)insertNewBookWithDate:(NSDate *)newDate; -(void)deleteBook:(Book *)book; -(NSArray *)fetchEntityOfType:(NSString *)entityType withPredicate:(NSPredicate *)predicate andSortKey:(NSString *)sortKey; @end 

持久Stack.m

 #import "PersistentStack.h" #import "AppDelegate.h" @interface PersistentStack () @property (nonatomic,strong,readwrite) NSManagedObjectContext* managedObjectContext; @property (nonatomic,strong) NSURL* modelURL; @property (nonatomic,strong) NSURL* storeURL; @end @implementation PersistentStack +(id)sharedInstance { static PersistentStack *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; sharedInstance = appDelegate.persistentStack; }); return sharedInstance; } - (id)initWithStoreURL:(NSURL*)storeURL modelURL:(NSURL*)modelURL { self = [super init]; if (self) { self.storeURL = storeURL; self.modelURL = modelURL; [self setupManagedObjectContext]; } return self; } - (void)setupManagedObjectContext { self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; self.managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; self.managedObjectContext.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; //__weak NSPersistentStoreCoordinator *psc = self.managedObjectContext.persistentStoreCoordinator; // iCloud notification subscriptions NSNotificationCenter *dc = [NSNotificationCenter defaultCenter]; [dc addObserver:self selector:@selector(storesWillChange:) name:NSPersistentStoreCoordinatorStoresWillChangeNotification object:self.managedObjectContext.persistentStoreCoordinator]; [dc addObserver:self selector:@selector(storesDidChange:) name:NSPersistentStoreCoordinatorStoresDidChangeNotification object:self.managedObjectContext.persistentStoreCoordinator]; [dc addObserver:self selector:@selector(persistentStoreDidImportUbiquitousContentChanges:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:self.managedObjectContext.persistentStoreCoordinator]; NSError* error; // the only difference in this call that makes the store an iCloud enabled store // is the NSPersistentStoreUbiquitousContentNameKey in options. I use "iCloudStore" // but you can use what you like. For a non-iCloud enabled store, I pass "nil" for options. // Note that the store URL is the same regardless of whether you're using iCloud or not. // If you create a non-iCloud enabled store, it will be created in the App's Documents directory. // An iCloud enabled store will be created below a directory called CoreDataUbiquitySupport // in your App's Documents directory [self.managedObjectContext.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:@{ NSPersistentStoreUbiquitousContentNameKey : @"iCloudStore" } error:&error]; if (error) { NSLog(@"error: %@", error); } } - (NSManagedObjectModel*)managedObjectModel { return [[NSManagedObjectModel alloc] initWithContentsOfURL:self.modelURL]; } // Subscribe to NSPersistentStoreDidImportUbiquitousContentChangesNotification - (void)persistentStoreDidImportUbiquitousContentChanges:(NSNotification*)note { NSLog(@"%s", __PRETTY_FUNCTION__); NSLog(@"%@", note.userInfo.description); NSManagedObjectContext *moc = self.managedObjectContext; [moc performBlock:^{ [moc mergeChangesFromContextDidSaveNotification:note]; [[NSNotificationCenter defaultCenter] postNotificationName:@"notifiCloudStoreDidChange" object:nil]; /* // you may want to post a notification here so that which ever part of your app // needs to can react appropriately to what was merged. // An exmaple of how to iterate over what was merged follows, although I wouldn't // recommend doing it here. Better handle it in a delegate or use notifications. // Note that the notification contains NSManagedObjectIDs // and not NSManagedObjects. NSDictionary *changes = note.userInfo; NSMutableSet *allChanges = [NSMutableSet new]; [allChanges unionSet:changes[NSInsertedObjectsKey]]; [allChanges unionSet:changes[NSUpdatedObjectsKey]]; [allChanges unionSet:changes[NSDeletedObjectsKey]]; for (NSManagedObjectID *objID in allChanges) { // do whatever you need to with the NSManagedObjectID // you can retrieve the object from with [moc objectWithID:objID] } */ }]; } // Subscribe to NSPersistentStoreCoordinatorStoresWillChangeNotification // most likely to be called if the user enables / disables iCloud // (either globally, or just for your app) or if the user changes // iCloud accounts. - (void)storesWillChange:(NSNotification *)note { NSLog(@"storeWillChange"); NSManagedObjectContext *moc = self.managedObjectContext; //[moc performBlockAndWait:^{ [moc performBlock:^{ NSError *error = nil; if ([moc hasChanges]) { [moc save:&error]; } [moc reset]; }]; // now reset your UI to be prepared for a totally different // set of data (eg, popToRootViewControllerAnimated:) // but don't load any new data yet. } // Subscribe to NSPersistentStoreCoordinatorStoresDidChangeNotification - (void)storesDidChange:(NSNotification *)note { // here is when you can refresh your UI and // load new data from the new store NSLog(@"storeDidChange"); [[NSNotificationCenter defaultCenter] postNotificationName:@"notifiCloudStoreDidChange" object:nil]; } #pragma mark - Regular Methods - -(Book *)insertNewBookWithDate:(NSDate *)newDate { Book *newBook = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:self.managedObjectContext]; newBook.bookName = @"Book"; newBook.publishDate = newDate; [self.managedObjectContext save:nil]; return newBook; } -(void)deleteBook:(Book *)book { [self.managedObjectContext deleteObject:book]; [self.managedObjectContext save:nil]; } -(NSArray *)fetchEntityOfType:(NSString *)entityType withPredicate:(NSPredicate *)predicate andSortKey:(NSString *)sortKey { NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:entityType inManagedObjectContext:self.managedObjectContext]; [fetchRequest setEntity:entity]; // Specify criteria for filtering which objects to fetch [fetchRequest setPredicate:predicate]; // Specify how the fetched objects should be sorted NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:YES]; [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]]; NSError *error = nil; NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; if (fetchedObjects == nil) { NSLog(@"couldn't fetch entity of type '%@', error: %@", entityType, error.localizedDescription); } return fetchedObjects; } @end 

我也遇到了类似的问题。 我会看见:

 Using local storage: 1 

但没有其他输出。 如果我重build应用程序,我会得到像这样的东西:

 Error adding store for new account: 

有一点要注意的是,我只会得到这个输出,如果我第一次按下iPhone上的“主页button”,然后重新打开应用程序。

关键要注意的是, 我没有select服务 。 为了解决这个问题,我select了“iCloud Documents”。

在重build之前,您可能需要删除应用程序。