有人在Xcode 6和iOS 8上获得过iCloud核心数据同步设置吗?(希望这不是重复的帖子)
iCloud Core数据存储选件到哪里去了?
我记得Core Data还有一个称为Core Data storage的额外存储选项,但是现在在Xcode 6中,当我在Xcode 6中启用iCloud切换时,它似乎仅显示键值和文档存储。
背景资料
- 新的iPad应用
- Xcode 6
- 定位最低版本的iOS 7,但希望它也适用于iOS 8?(我们可以将iOS 8设置为最低)
- 想要使用iCloud Core数据存储而不是键值存储或文档存储。
- 在Simulator和iPad设备的``设置''>``iCloud''中登录了相同的Apple帐户
- 我的配置文件用于对应用程序进行代码签名,已为开发和分发启用了iCloud(由Xcode自动启用)
我的设定
到目前为止,我不知道我是否已正确设置Core Data iCloud。
Xcode似乎已在iOS开发人员门户中设置了iCloud容器:
iCloud.com.xxxxxx.xxxxxxxx (note: I've replaced the actual strings with xxxx here)
我的Xcode 6 iCloud“服务”列表在以下位置旁边没有任何刻度:
- 键值存储
- iCloud文件
- CloudKit
由于它没有列出“核心数据”作为存储选项,因此我们现在应该使用哪一个?
在“服务”正下方的“容器”中,其显示为灰色的以下选项:
- 使用默认容器(默认选中该容器)
- 指定自定义容器
- iCloud.com.xxxxxxxxxx.xxxxxxxxx(再次用xxxx代替真实标识符)
我无法选择任何选项,似乎迫使我“使用默认容器”。
最后,Xcode似乎在以下方面显示了滴答声:
- 将“ iCloud”权利添加到您的应用ID
- 将“ iCloud容器”权利添加到您的应用程序ID
- 将“ iCloud”权利人添加到您的权利文件中
- 链接CloudKit.framework
因此,通过Xcode自己的自动化流程,它可以为我设置一切。
参考代码
好的,所以我环顾四周,注意到这里写了一个iCloud堆栈:
https://github.com/mluisbrown/iCloudCoreDataStack
我已经采用了必要的代码,并尝试适应我的Core Data Manager单例:
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 Simulator(我相信它是iOS 8模拟器)和运行iOS 7.x的iPad设备上运行该应用程序
我在模拟器上用用户输入的名称创建了一个相册,但是没有看到iPad设备显示新创建的相册。我也尝试过颠倒角色,iPad设备创建,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中的“停止”按钮),则会看到以下消息:
-[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](808): CoreData: Ubiquity: nobody~sim301AE3E8-16B2-5A08-917D-7B55D1879BE4:iCloudStore
Using local storage: 1
我读到“使用本地存储:0”是理想的状态?并且1表示本地设备数据存储而不是iCloud数据存储。
当我创建专辑时,保存它,停止模拟器,然后再次启动该应用程序,我的专辑消失了,但是在我创建新专辑后,先前的所有专辑立即又神奇地再次出现。有点奇怪 如果我不使用iCloud并将代码还原为以前的设置,则可以创建并查看专辑,无论是否最小化我的应用程序或重新启动应用程序,但我没有所需的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 Drive帐户才能运行吗?
超级困惑@ _ @
iOS 8解决方案:
好...然后... 我想我解决了。
新发现。浏览完此页面后:
http://www.tuaw.com/2014/09/17/psa-do-not-not-upgrade-to-icloud-drive-during-ios-8-installation/
它说:
iCloud Drive是Apple新增和改进的iCloud同步和文件存储功能,可让您在iOS 8设备和运行OS X 10 Yosemite的Mac之间共享文档。
因此,我决定硬着头皮将我的iCloud帐户升级到iCloud驱动器(免费升级)。
升级到iCloud驱动器并重新运行我的应用程序后,对Xcode 6进行了一些更改,现在可以正常使用了。
一些重要的注意事项:
- iCloud Drive与以前的iCloud文档和数据存储不兼容。因此,如果要进行测试,请确保所有设备都使用iCloud驱动器和iOS 8。
- 在启动应用程序后,模拟器似乎只同步一次,而设备则在每个间隔持续同步。不知道这是否是模拟器错误。也许我的配置不完美。
- 首次尝试使用“使用默认容器”对我来说在模拟器中不起作用(但在它可以工作的设备上),也许需要删除该应用程序的先前副本并重新安装。首先尝试使用默认容器,看看它是否有效,否则,请阅读下面的要点。
-
由于上述原因,我改为使用具有这种模式的Ubiquity容器:
iCloud。$(CFBundleIdentifier)
所以像:
iCloud.com.xxxxxxxx.iCloudCoreDataDemo
其中“ xxxxxxxx”是我的公司名称标识符。
我通过登录iOS开发人员中心制作了上述iCloud容器,也许您只需按Xcode 6内的“ +”号,然后在其中输入一个即可,Xcode应该自动为您设置所有内容。
我用来测试它是否正常工作的代码块是:
- (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解决方案:
好的,所以我刚刚发现了一些东西,并且设法使其仅适用于iOS 7。我仍然没有想出如何在iOS 8中做到这一点,但我注意到了一些重要的事情。
在运行iOS 8.0.2的iPhone 5上,我不再在iCloud设置菜单中拥有“文档和数据”选项。
但是,在运行iOS 7的iPad上,我确实看到了“文档和数据”选项。
也许这就是为什么它不能在iOS 8上运行的原因,我们不再拥有文档和数据存储了?
无论如何,这就是我发现的仅适用于iOS 7的解决方案。
我在这里找到此页面
其中一行说:
- iCloud文档存储用于用户可见的基于文件的内容,Core Data存储或其他复杂的基于文件的内容。
果然,我进入了Xcode 6项目文件,并勾选了“ iCloud文档”选项。这使单选按钮变为灰色,但我仍将其保留在“使用默认容器”中。
我了解到的一件事是,我需要在appDelegate中初始化PersistentStack。以前,我尝试在+(id)sharedInstance方法内初始化持久性堆栈,但它导致iCloud仅在第一次同步,因此在初始加载和同步后,添加新记录之后就不会同步。
我重写了一个基本应用程序,并稍微修改了持久性堆栈:
应用程序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"];
}
持久堆栈
#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
持久堆栈
#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
但没有其他输出。如果我重新构建应用程序,我将得到类似以下内容:
Error adding store for new account:
需要注意的一件事是,只有先按iPhone上的“主页”按钮,然后重新打开应用程序,我才能获得此输出。
需要注意的关键一点是我没有选择任何服务。为了解决此问题,我选择了“ iCloud文档”。
重建之前,您可能需要删除该应用程序。
评论已关闭!