Configuration des données de base de Xcode 6 iOS 8 iCloud

Quelqu'un at-il la configuration de synchronisation des données de base iCloud sur Xcode 6 et iOS 8? (J'espère que ce n'est pas un message en double)

Où est passée l'option de stockage de données Core iCloud?

Je me souviens que Core Data avait une option de stockage supplémentaire appelée stockage de données de base, mais maintenant dans Xcode 6, il semble seulement montrer la valeur-key et le stockage de documents quand j'active l'iCloud basculer dans Xcode 6.

Informations de fond

  • Nouvelle application iPad
  • Xcode 6
  • Ciblant la version minimale iOS 7 mais en espérant que cela fonctionne aussi pour iOS 8? (Nous pouvons définir iOS 8 au minimum)
  • Vous souhaitez utiliser le stockage de données Core iCloud à la place de la valeur-key ou du stockage de documents.
  • Vous êtes connecté au même count Apple dans les Paramètres> iCloud pour simulateur et iPad
  • Mon profil d'approvisionnement utilisé pour le code de signature de l'application a iCloud activé pour le développement et la dissortingbution (a été automatiquement activé par Xcode)

Ma configuration

Jusqu'à présent, je ne sais pas si j'ai configuré Core Data iCloud correctement.

Xcode semble avoir configuré les conteneurs iCloud dans le portail de développeur iOS:

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

Ma list de «services» de Xcode 6 iCloud ne montre aucune coche à côté de:

  • Stockage de valeur-key
  • documents iCloud
  • CloudKit

Lequel devrions-nous utiliser maintenant puisqu'il ne list pas les "données de base" comme option de stockage?

Dans les "Conteneurs" directement sous les "services", les options suivantes sont grisées:

  • Utiliser le conteneur par défaut (celui-ci est coché par défaut)
  • Spécifiez des conteneurs personnalisés
  • iCloud.com.xxxxxxxxxx.xxxxxxxxx (encore une fois, substitué les identifiants réels par xxxx)

Je ne peux choisir aucune option, il semble me forcer à "Utiliser le conteneur par défaut".

Enfin, Xcode semble montrer des tics pour:

  • Ajouter le droit "iCloud" à votre identifiant d'application
  • Ajouter le droit "Conteneurs iCloud" à votre ID d'application
  • Ajoutez les droits "iCloud" à votre file de droits
  • Lier CloudKit.framework

Ainsi, grâce au process automatisé de Xcode, tout est configuré pour moi.

Le code de reference

OK, donc je lis et remarque une stack iCloud écrit ici:

https://github.com/mluisbrown/iCloudCoreDataStack

J'ai pris le code nécessaire et j'ai essayé de m'adapter à mon singleton Core Data Manager:

Fichier DataManager.h

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

Fichier DataManager.m

 @property (nonatomic, strong) NSManagedObjectModel *managedObjectModel; - (NSSsortingng *)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; } - (NSSsortingng *)modelName { return @"Albums"; } - (NSSsortingng *)pathToModel { return [[NSBundle mainBundle] pathForResource:[self modelName] ofType:@"momd"]; } - (NSSsortingng *)storeFilename { return [[self modelName] ssortingngByAppendingPathExtension:@"sqlite"]; } - (NSSsortingng *)pathToLocalStore { return [[self documentsDirectory] ssortingngByAppendingPathComponent:[self storeFilename]]; } - (NSSsortingng *)documentsDirectory { NSSsortingng *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]; NSSsortingng *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 resortingeve 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:(NSSsortingng *)entityType UsingPredicated:(NSPredicate *)predicate sortBy:(NSSsortingng *)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; } 

Mes observations

J'ai essayé de lancer l'application sur l'iPad Simulator (je crois que c'est le simulateur iOS 8) et sur un appareil iPad fonctionnant sous iOS 7.x

J'ai créé un album avec un nom entré par l'user sur le simulateur, mais je ne vois pas l'appareil iPad montrant l'album nouvellement créé. J'ai également essayé d'inverser les rôles, créer un appareil iPad, simulateur iOS aucun résultat non plus.

Je vois mes messages de journal:

 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 

Si je minimise l'application dans le simulateur et l'ouvre de nouveau (sans appuyer sur le button Stop dans Xcode), je vois ces message:

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

J'ai lu que "Utiliser le stockage local: 0" est ce qu'il devrait idéalement être? et cela signifie 1 magasin de données de périphérique local plutôt que le magasin de données iCloud.

Lorsque je crée un album, le sauvegarde, arrête le simulateur, redémarre l'application, mes albums disparaissent, mais immédiatement après la création d'un nouvel album, tout l'album précédent réapparaît comme par magie. C'est un peu bizarre. Si je n'utilise pas iCloud et que je ramène mon code à la configuration précédente, je peux créer et voir mon album correctement, que je réduise mon application ou non, ou que je redémarre l'application, mais je n'ai pas la synchronisation iCloud dont j'ai besoin .

Ai-je fait des erreurs n'importe où?

Désolé pour le long message, mais est-ce que quelqu'un a déjà travaillé sur iCloud pour iOS 8 et Xcode 6?

J'ai vraiment besoin d'aide.

Questions supplémentaires

1) iOS 8 nécessite-t-il l'utilisation de cet identifiant de conteneur? (que Xcode 6 a généré pour moi):

 com.apple.developer.icloud-container-identifiers 

Ce n'est pas ce que l'iOS 7 ressemble à droite? iOS 7 on est plus comme:

 com.apple.developer.ubiquity-container-identifiers 

2) Ai-je besoin d'un count iCloud Drive avant que cela fonctionne?

Super confus @ _ @

iOS 8 Solution:

OK … alors … lol. Je pense que je l'ai résolu.

Nouvelle découverte Après avoir parcouru cette page:

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

Ça dit:

iCloud Drive est la nouvelle fonctionnalité améliorée de synchronisation et de stockage de files d'Apple qui vous permet de partager des documents entre vos appareils iOS 8 et votre Mac fonctionnant sous OS X 10 Yosemite.

J'ai donc décidé de mordre la balle et de mettre à niveau mon count iCloud sur le lecteur iCloud (gratuit pour mettre à niveau).

Après la mise à niveau vers le lecteur iCloud, et ré-exécuté mon application avec quelques modifications Xcode 6, cela fonctionne maintenant.

Quelques choses importantes à noter:

  • Le lecteur iCloud est incompatible avec le précédent stockage de documents et de données iCloud. Donc, si vous allez tester, assurez-vous que tous vos appareils utilisent le lecteur iCloud et iOS 8.
  • Le simulateur ne semble synchroniser qu'une seule fois, après le lancement de l'application pendant que l'appareil synchronise en permanence chaque intervalle. Je ne sais pas si c'est un bug de simulateur ou non. Ou peut-être que ma configuration n'est pas parfaite.
  • Utiliser "Utiliser les conteneurs par défaut" ne fonctionne pas dans le simulateur pour moi (mais sur l'appareil, il fonctionne) au premier essai, peut-être besoin de supprimer la copy précédente de l'application et réinstaller. Essayez d'abord d'utiliser les conteneurs par défaut et voyez si cela fonctionne, sinon, lisez le point suivant ci-dessous.
  • Pour la raison ci-dessus, j'ai changé pour utiliser un conteneur Ubiquity avec ce model:

    iCloud. $ (CFBundleIdentifier)

Donc, quelque chose comme:

 iCloud.com.xxxxxxxx.iCloudCoreDataDemo 

Où "xxxxxxxx" est l'identifiant de mon entreprise.

J'ai fait le conteneur iCloud ci-dessus en me connectant à mon iOS Developer Center, peut-être que vous pourriez simplement appuyer sur le signe "+" à l'intérieur de Xcode 6 et en entrer un, Xcode devrait automatiquement configurer tout pour vous.

Un bloc de code que j'ai l'habitude de tester pour voir si ça fonctionne est le suivant:

 - (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; } 

Si vous voyez "hourra?" alors ça va, vous devriez aussi voir ce model de text dans votre sortie console 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 

Notez les deux lignes importantes:

 Using local storage: 1 

devient plus tard:

 Using local storage: 0 

Le stockage local 1 signifie qu'il utilise actuellement le stockage local, tandis que le stockage local 0 signifie qu'il a déplacé datatables vers le stockage iCloud.

J'espère que cela profite à tout le monde.

iOS 7 seulement solution:

OK, donc je viens de découvrir quelque chose et j'ai réussi à le faire fonctionner pour iOS 7 seulement. Je n'ai toujours pas compris comment le faire dans iOS 8 mais j'ai remarqué quelque chose d'important.

Sur mon iPhone 5 exécutant iOS 8.0.2, je n'ai plus l'option " Document & Data " dans le menu des parameters d'iCloud.

Cependant, sur mon iPad fonctionnant sous iOS 7, je vois les options "Document & Data".

Peut-être que c'est la raison pour laquelle cela ne fonctionne pas sur iOS 8, nous n'avons plus de stockage de documents et de données?

De toute façon, voici ce que j'ai découvert pour iOS 7 seule solution.

J'ai trouvé cette page ici

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

et l'un de la ligne dit:

  • Le stockage de documents iCloud est destiné au contenu basé sur des files visible par l'user, au stockage des données de base ou à d'autres contenus complexes basés sur des files.

Effectivement, je suis allé dans mon file de projet Xcode 6 et j'ai coché l'option "Documents iCloud". Cela n'a pas grisé les buttons radio, mais je l'ai quand même laissé à "Use default Containers".

Une chose que j'ai apprise est que je dois initier mon PersistentStack dans l'appDelegate. Auparavant, j'essayais d'initialiser la stack persistante dans la méthode + (id) sharedInstance mais cela faisait que l'iCloud ne se synchronisait que la première fois, donc après le chargement initial et la synchronisation, l'ajout d'un nouvel logging n'est pas synchronisé par la suite.

J'ai réécrit une application basique et j'ai légèrement modifié la stack persistante:

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 persistante

 #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:(NSSsortingng *)entityType withPredicate:(NSPredicate *)predicate andSortKey:(NSSsortingng *)sortKey; @end 

Stack.m persistant

 #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 resortingeve 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:(NSSsortingng *)entityType withPredicate:(NSPredicate *)predicate andSortKey:(NSSsortingng *)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 

J'ai lutté avec un problème similaire. Je verrais:

 Using local storage: 1 

mais pas d'autre sortie. Et si je reconstruisais l'application, j'aurais quelque chose comme:

 Error adding store for new account: 

Une chose à noter est que je n'obtiendrais cette sortie que si j'appuie d'abord sur le "button d'accueil" sur l'iPhone, puis j'ai rouvert l'application.

Une chose importante à noter est que je n'avais aucun service sélectionné . Pour résoudre ce problème, j'ai sélectionné "Documents iCloud".

Vous devrez peut-être supprimer l'application avant de la rebuild.