ios - para - icloud fotos
Configuración de datos básicos de iCloud de Xcode 6 iOS 8 (2)
¿Alguien ha obtenido la configuración de sincronización de datos del núcleo de iCloud en Xcode 6 e iOS 8? (afortunadamente esta no es una publicación duplicada)
¿A dónde se dirigió la opción de almacenamiento iCloud Core Data?
Recuerdo que Core Data tenía una opción de almacenamiento adicional llamada Core Data storage, pero ahora en Xcode 6 solo parece mostrar valor clave y almacenamiento de documentos cuando habilito el alternar de iCloud en Xcode 6.
Información de fondo
- Nueva aplicación para iPad
- Xcode 6
- ¿Dirigiéndose a la versión mínima iOS 7 pero esperando que también funcione para iOS 8? (Podemos configurar iOS 8 como mínimo)
- Desea utilizar el almacenamiento de iCloud Core Data en lugar del valor clave o el almacenamiento de documentos.
- Ha iniciado sesión en la misma cuenta de Apple en Configuración> iCloud para el simulador y el dispositivo iPad
- Mi perfil de aprovisionamiento utilizado para firmar con código la aplicación tiene iCloud habilitado para desarrollo y distribución (fue habilitado automáticamente por Xcode)
Mi configuración
Hasta ahora, no sé si configuré Core Data iCloud correctamente.
Xcode parece haber configurado los contenedores de iCloud en el Portal para desarrolladores de iOS:
iCloud.com.xxxxxx.xxxxxxxx (note: I''ve replaced the actual strings with xxxx here)
Mi lista de "servicios" de Xcode 6 iCloud no muestra tics al lado de:
- Almacenamiento de valor clave
- documentos de iCloud
- CloudKit
¿Cuál deberíamos estar usando ahora ya que no enumera los "datos centrales" como una opción de almacenamiento?
En los "Contenedores" directamente debajo de los "servicios", muestra las siguientes opciones en gris:
- Usar contenedor predeterminado (este marcado por defecto)
- Especificar contenedores personalizados
- iCloud.com.xxxxxxxxxx.xxxxxxxxx (nuevamente, sustituyó los identificadores reales por xxxx)
No puedo elegir ninguna opción, parece forzarme a "Usar contenedor predeterminado".
Finalmente, Xcode parece mostrar tics para:
- Agregue el derecho de "iCloud" a su ID de aplicación
- Agregue el derecho de "contenedores de iCloud" a su ID de aplicación
- Agregue los titulares de derechos de "iCloud" a su archivo de derechos
- Enlace CloudKit.framework
Entonces, mediante el proceso automático de Xcode, configuró todo para mí.
El código de referencia
OK, entonces leo y noto una pila de iCloud escrita aquí:
https://github.com/mluisbrown/iCloudCoreDataStack
Tomé el código necesario e intenté adaptarme a mi Singleton del administrador de datos centrales:
Archivo 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;
Archivo 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;
}
Mis observaciones
Intenté ejecutar la aplicación en el simulador de iPad (creo que es el simulador de iOS 8) y en el dispositivo de iPad con iOS 7.x
Creé un álbum con un nombre ingresado por el usuario en el simulador, pero no veo el dispositivo iPad que muestre el álbum recién creado. También traté de invertir los roles, crear dispositivo iPad, simulador iOS sin resultados.
Veo mis mensajes de registro:
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 minimizo la aplicación en el simulador y la vuelvo a abrir (sin presionar el botón Detener en Xcode), veo este mensaje:
-[PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:](808): CoreData: Ubiquity: nobody~sim301AE3E8-16B2-5A08-917D-7B55D1879BE4:iCloudStore
Using local storage: 1
Leí que "Usar almacenamiento local: 0" es lo que idealmente debería ser? y que 1 significa almacén de datos del dispositivo local en lugar de almacenamiento de datos iCloud.
Cuando creo un álbum, lo guardo, dejo el simulador, luego vuelvo a iniciar la aplicación, mis álbumes desaparecen, pero inmediatamente después de crear un nuevo álbum, todos los álbumes anteriores vuelven a aparecer mágicamente. Es un poco extraño. Si no uso iCloud y revertí mi código a la configuración anterior, puedo crear y ver mi álbum correctamente, independientemente de si minimizo mi aplicación o no, o reinicio la aplicación, pero luego no tengo la sincronización de iCloud que necesito .
¿He cometido algún error en alguna parte?
Perdón por la publicación larga pero ¿alguien ha conseguido que iCloud trabaje para iOS 8 y Xcode 6?
Realmente podría usar algo de ayuda.
Preguntas adicionales
1) ¿Requiere iOS 8 el uso de este identificador de contenedor? (que Xcode 6 generó para mí):
com.apple.developer.icloud-container-identifiers
Eso no es lo que parece el iOS 7, ¿verdad? iOS 7 uno es más como:
com.apple.developer.ubiquity-container-identifiers
2) ¿Necesito una cuenta de iCloud Drive antes de que funcione?
Súper confundido @ _ @
Solución iOS 8:
OK ... entonces ... jaja. Creo que lo resolví
Nuevo descubrimiento. Después de hojear esta página:
http://www.tuaw.com/2014/09/17/psa-do-not-upgrade-to-icloud-drive-during-ios-8-installation/
Dice:
iCloud Drive es la nueva y mejorada función de sincronización y almacenamiento de archivos iCloud de Apple que le permite compartir documentos entre sus dispositivos iOS 8 y su Mac con OS X 10 Yosemite.
Por lo tanto, decidí morder la bala y actualizar mi cuenta de iCloud a la unidad iCloud (de forma gratuita para actualizar).
Después de actualizar a la unidad iCloud, y volver a ejecutar mi aplicación con algunos cambios de Xcode 6, está funcionando ahora.
Algunas cosas importantes a tener en cuenta:
- iCloud Drive es incompatible con el almacenamiento previo de documentos y datos de iCloud. Entonces, si vas a probar, asegúrate de que todos tus dispositivos estén usando la unidad iCloud y iOS 8.
- El simulador solo parece sincronizarse una vez, después de iniciar la aplicación mientras el dispositivo sincroniza continuamente cada intervalo. No estoy seguro si es un error del simulador o no. O tal vez mi configuración no es perfecta.
- El uso de "Usar contenedores predeterminados" no funciona en el simulador para mí (pero en el dispositivo sí funciona) en el primer intento, tal vez sea necesario eliminar la copia anterior de la aplicación y volver a instalarla. Intente usar contenedores predeterminados primero y vea si funciona, de lo contrario, lea el siguiente punto a continuación.
Por la razón anterior, cambié a usar un contenedor Ubiquity con este patrón:
iCloud. $ (CFBundleIdentifier)
Entonces algo así como:
iCloud.com.xxxxxxxx.iCloudCoreDataDemo
Donde "xxxxxxxx" es el identificador del nombre de mi compañía.
Hice el contenedor anterior de iCloud iniciando sesión en mi iOS Developer Center, quizás podrías simplemente presionar el signo "+" dentro de Xcode 6 e ingresar uno allí, Xcode debería configurar todo automáticamente para ti.
Un bloque de código que usé para probar para ver si está funcionando es este:
- (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 ves "¿hurra?" entonces está bien, también debería ver este patrón de texto en la salida de su consola 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
Observe las dos líneas importantes:
Using local storage: 1
más tarde se convierte en:
Using local storage: 0
El almacenamiento local 1 significa que actualmente está utilizando el almacenamiento local, mientras que el almacenamiento local 0 significa que ha movido los datos al almacenamiento de iCloud.
Espero que esto beneficie a todos los demás.
Solución solo para iOS 7:
De acuerdo, acabo de descubrir algo y logré que funcione solo para iOS 7 . Todavía no he descubierto cómo hacerlo en iOS 8, pero he notado algo importante.
En mi iPhone 5 con iOS 8.0.2, ya no tengo la opción " Documento y datos " en el menú de configuración de iCloud.
Sin embargo, en mi iPad con iOS 7, veo las opciones de "Documento y datos".
Quizás esta es la razón por la cual no funciona en iOS 8, ¿ya no tenemos el almacenamiento de documentos y datos?
De todos modos, esto es lo que descubrí para la solución única de iOS 7.
Encontré esta página aquí
y uno de la línea dice:
- El almacenamiento de documentos de iCloud es para contenido basado en archivos visible para el usuario, almacenamiento de Datos centrales o para otro contenido complejo basado en archivos.
Efectivamente, entré en mi archivo de proyecto Xcode 6 y marqué la opción "Documentos de iCloud". Esto deshizo los botones de opción, pero aún lo dejé en "Usar contenedores predeterminados".
Una cosa que aprendí es que necesito iniciar mi PersistentStack en la aplicaciónDelegate. Previamente, traté de iniciar la pila persistente dentro del método + (id) sharedInstance, pero causó que iCloud se sincronizara solo la primera vez, por lo que después de la carga inicial y la sincronización, la adición de un nuevo registro no se sincroniza posteriormente.
Reescribí una aplicación básica y modifiqué ligeramente la pila persistente:
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 persistente.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 permanente
#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
Luché con un problema similar. Yo vería:
Using local storage: 1
pero ninguna otra salida. Y si reconstruyera la aplicación obtendría algo así como:
Error adding store for new account:
Una cosa a tener en cuenta es que solo obtendría esta salida si primero presiono el "botón de inicio" en el iPhone, y luego volví a abrir la aplicación.
Una cosa clave a tener en cuenta es que no tuve servicios seleccionados . Para solucionar este problema, seleccioné "Documentos de iCloud".
Es posible que deba eliminar la aplicación antes de reconstruirla.