2015-09-01 16 views
11

Ho un'applicazione per OSX e iOS e entrambi utilizzano iCloud per condividere i dati di base tra di loro. Quando apporto le modifiche nell'iPhone, posso vederle nell'app OSX e lo NSPersistentStoreDidImportUbiquitousContentChangesNotification viene chiamato in entrambe le app, quindi iOS -> Mac funziona bene. Ma quando apporto alcune modifiche all'app per Mac non riesco a vederle nell'iPhone. L'iPhone non chiama mai lo NSPersistentStoreDidImportUbiquitousContentChangesNotification. L'unico modo per ottenere le modifiche al Mac è apportare alcune modifiche su iPhone. Quindi posso vedere tutte le modifiche.iCloud Core Condivisione dei dati tra OSX e iOS

L'integrazione di iCloud in entrambi i progetti è la stessa. La datamodel dei dati di base è la stessa. I diritti sono entrambi uguali.

Tutto il mio codice si basa su questa libreria: http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/

Perché l'iPhone non ottenere modifiche Mac finché io ponga qualche cambiamento a iPhone? Qualche idea?

Un'altra domanda

Nella mia app quando l'utente abilita icloud verifico se è già un file a iCloud. Se il file esiste, l'utente può scegliere di ripristinare i dati principali dal file iCloud o avviare una nuova copia dal negozio locale. Per iniziare una nuova copia di questo codice:

- (void)startNewCopy 
{ 
    [self removeICloudStore]; 
    [self moveStoreToIcloud]; 
} 

- (void)removeICloudStore 
{ 
    BOOL result; 
    NSError *error; 
    // Now delete the iCloud content and file 
    result = [NSPersistentStoreCoordinator removeUbiquitousContentAndPersistentStoreAtURL:[self icloudStoreURL] 
                      options:[self icloudStoreOptions] 
                      error:&error]; 
    if (!result) 
    { 
     NSLog(@"Error removing store"); 
    } 
    else 
    { 
     NSLog(@"Core Data store removed."); 
     // Now delete the local file 
     [self deleteLocalCopyOfiCloudStore]; 
    } 

} 


- (void)deleteLocalCopyOfiCloudStore { 
    // We need to get the URL to the store 
    NSError *error = nil; 
    [[NSFileManager defaultManager] removeItemAtURL:[self localUbiquitySupportURL] error:&error]; 
} 

- (void)moveStoreToIcloud 
{ 
    // Open the store 
    NSPersistentStore *sourceStore = [[_persistentStoreCoordinator persistentStores] firstObject]; 

    if (!sourceStore) 
    { 
     NSLog(@" failed to add old store"); 
    } 
    else 
    { 
     NSLog(@" Successfully added store to migrate"); 
     NSError *error; 
     id migrationSuccess = [_persistentStoreCoordinator migratePersistentStore:sourceStore toURL:[self icloudStoreURL] options:[self icloudStoreOptions] withType:NSSQLiteStoreType error:&error]; 

     if (migrationSuccess) 
     { 
      NSLog(@"Store migrated to iCloud"); 

      _persistentStoreCoordinator = nil; 
      _managedObjectContext = nil; 

      // Now delete the local file 
      [self deleteLocalStore]; 

     } 
     else 
     { 
      NSLog(@"Failed to migrate store: %@, %@", error, error.userInfo); 

     } 
    } 

} 

- (void)deleteLocalStore 
{ 
    NSError *error = nil; 
    [[NSFileManager defaultManager] removeItemAtURL:[self localStoreURL] error:&error]; 
} 

In questo modo da un unico dispositivo tutto sembra funzionare bene, ma quando provo questo con più dispositivi sto ottenendo alcuni errori.

Esempio:

Ho due dispositivi. Il primo non è connesso a iCloud e il secondo è connesso a iCloud. Nel primo dispositivo quando abilito iCloud scelgo startNewCopy e poi nel secondo dispositivo ottengo questo errore:

CoreData: Ubiquity: Librarian returned a serious error for starting downloads Error Domain=BRCloudDocsErrorDomain Code=5 "The operation couldn’t be completed. (BRCloudDocsErrorDomain error 5 - No document at URL)"

Il NSPersistentStoreCoordinatorStoresDidChangeNotification non è mai chiamato prima dell'errore.

Questo è il mio codice per la notifica:

- (void)processStoresDidChange:(NSNotification *)notification 
{ 
     NSLog(@"processStoresDidChange"); 
     // Post notification to trigger UI updates 

     // Check type of transition 
     NSNumber *type = [notification.userInfo objectForKey:NSPersistentStoreUbiquitousTransitionTypeKey]; 

     //NSLog(@" userInfo is %@", notification.userInfo); 
     //NSLog(@" transition type is %@", type); 

     if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted) { 

      NSLog(@" transition type is NSPersistentStoreUbiquitousTransitionTypeInitialImportCompleted"); 

     } else if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeAccountAdded) { 
      NSLog(@" transition type is NSPersistentStoreUbiquitousTransitionTypeAccountAdded"); 
     } else if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeAccountRemoved) { 
      NSLog(@" transition type is NSPersistentStoreUbiquitousTransitionTypeAccountRemoved"); 
     } else if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeContentRemoved) { 
      NSLog(@" transition type is NSPersistentStoreUbiquitousTransitionTypeContentRemoved"); 
     } 

     [[NSOperationQueue mainQueue] addOperationWithBlock:^ { 

      if (type.intValue == NSPersistentStoreUbiquitousTransitionTypeContentRemoved) { 

       [self deleteLocalStore]; 
       _persistentStoreCoordinator = nil; 
       _managedObjectContext = nil; 

       NSLog(@" iCloud store was removed! Wait for empty store"); 
      } 

      // Refresh user Interface 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"notiIcloud" object:@"storeChanged"]; 
     }]; 

} 

Come posso rilevare che il contenuto iCloud è stato rimosso ed evitare di ottenere l'errore di cui sopra?

+0

Questo in realtà non risponde alla tua domanda, ma ho rinunciato a utilizzare Core Data con il supporto iCloud molto tempo fa. Ho quindi scritto la mia sincronizzazione, ma era un po 'limitato. Poi ho trovato Ensembles (http://www.ensembles.io) e lo sto usando da allora. È stato fantastico per me. C'è una versione open-source gratuita. –

+0

Thx per la risposta, ma preferisco usare il supporto iCloud standard di Apple. – user3065901

+0

Buona fortuna a te! –

risposta

0

Mi sembra che potresti non utilizzare le interfacce appropriate.

È possibile spostare i file dentro e fuori iCloud senza utilizzare i metodi NSPersistentStore. Spesso l'azione appropriata deve anche essere racchiusa in una chiamata NSFileCoordinator.

Ecco cosa faccio su iOS. toLocal indica una mossa da o storage locale (dispositivo):

// 
/// Move file between stores (assumed no name clash). 
/// Return new URL. 
/// Note: cloud file moves are asynchronous. 
/// 
- (NSURL *)moveStoreFile:(NSURL *)url toRootURL:(NSURL *)rootURL toLocal:(BOOL)toLocal 
{ 
    NSURL *newURL = rootURL; 
    if (!toLocal) 
     newURL = [newURL URLByAppendingPathComponent:@"Documents"]; 
    newURL = [newURL URLByAppendingPathComponent:url.lastPathComponent]; 

    [self backupFile:url isLocal:!toLocal completionHandler: 
    ^(BOOL success) { 

     MRLOG(@"MOVE %s %@ to %s %@", toLocal? "icloud" : "local", [url lastPathComponent], 
       toLocal? "local" : "icloud", [newURL lastPathComponent]); 

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
     ^{ 
      NSError *error; 
      // setUbiquitous does file coordination 
      BOOL msuccess = [[NSFileManager defaultManager] 
          setUbiquitous:!toLocal itemAtURL:url destinationURL:newURL error:&error]; 

      dispatch_async(dispatch_get_main_queue(), 
      ^{ 
       if (!msuccess) 
        MRLOG(@"move failed: %@", error); 
       [self.delegate moveStoreFileCompletedWithStatus:success error:error]; 
      }); 
     }); 
    }]; 

    return newURL; 
} 

eliminazione richiede un coordinamento file esplicito:

/// 
/// Purge backup file (really delete it). 
/// Note: cloud deletes are asynchronous. 
/// 
- (void)purgeFile:(NSURL *)url isLocal:(BOOL)isLocal 
{ 
    MRLOG(@"PURGE %s %@", isLocal? "local" : "icloud", [url lastPathComponent]); 

    if (isLocal) 
     [self removeFile:url]; 
    else 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
     ^{ 
      NSError *coordinationError; 
      NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil]; 

      [coordinator coordinateWritingItemAtURL:url options:NSFileCoordinatorWritingForDeleting 
                error:&coordinationError 
            byAccessor: 
      ^(NSURL* writingURL) 
      { 
       [self removeFile:writingURL]; 
      }]; 
      if (coordinationError) { 
       MRLOG(@"coordination error: %@", coordinationError); 
       [(SSApplication *)[SSApplication sharedApplication] fileErrorAlert:coordinationError]; 
      } 
     }); 
} 

per rilevare le modifiche ai file è necessario utilizzare NSMetadataQuery e aggiungere un osservatore per NSMetadataQueryDidUpdateNotification.

0

Ho avuto un problema simile sincronizzando iOS con il mio Mac.

Questo errore 5 indica effettivamente che c'è un problema con il tuo negozio.

Si può provare questi passaggi:

  • Su iOS è necessario ripristinare il contenuto del tuo simulatore e anche svuotare la contenuti iCloud (solo per la vostra applicazione).

È possibile ripristinare il contenuto di iCloud chiamando (scusate ho in Swift):

try! NSPersistentStoreCoordinator.removeUbiquitousContentAndPersistentStoreAtURL(storeURL, options: self.options) 
  • In Mac OS è necessario rimuovere il contenuto di questa cartella "CoreDataUbiquitySupport/YourAppId ". Questo è fondamentalmente il tuo archivio persistente dei dati principali (ad es .: file SQLite).

Questo problema si verifica quando il modello (file xcdatamodeld) è stato modificato e i dati esistenti non sono stati cancellati. Si finisce per avere un nuovo modello associato ai dati generati con un modello precedente e si sta tentando di sincronizzare questo mix tra dispositivi ...

In futuro, per evitare il problema relativo al modello, dare un'occhiata al Core Version del modello di dati e migrazione dei dati. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/Introduction.html

Spero che risolva il tuo problema.

Problemi correlati