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了这个页面
其中一行说:
- 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之前,您可能需要删除应用程序。