2012-10-23 57 views
1

我使用以下代碼將我的核心數據與iCloud同步。然而,我只是想讓它同步。例如,只能在wifi上同步。我能做到這一點嗎?這裏是我的代碼:如何控制iCloud何時同步我的核心數據?

- (NSManagedObjectContext *)managedObjectContext { 

    if (managedObjectContext != nil) { 
     return managedObjectContext; 
    } 

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 

    if (coordinator != nil) { 
     NSManagedObjectContext* moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

     [moc performBlockAndWait:^{ 
      [moc setPersistentStoreCoordinator: coordinator]; 
      [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(mergeChangesFrom_iCloud:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:coordinator]; 
     }]; 
     managedObjectContext = moc; 

     managedObjectContext.mergePolicy = [[NSMergePolicy alloc] 
              initWithMergeType:NSMergeByPropertyObjectTrumpMergePolicyType]; 
    } 

    return managedObjectContext; 
} 

- (void)mergeChangesFrom_iCloud:(NSNotification *)notification { 

    NSLog(@"Merging in changes from iCloud..."); 

    NSManagedObjectContext* moc = [self managedObjectContext]; 

    [moc performBlock:^{ 

     [moc mergeChangesFromContextDidSaveNotification:notification]; 

     NSNotification* refreshNotification = [NSNotification notificationWithName:@"SomethingChanged" 
                      object:self 
                      userInfo:[notification userInfo]]; 

     [[NSNotificationCenter defaultCenter] postNotification:refreshNotification]; 
    }]; 
} 
- (NSManagedObjectModel *)managedObjectModel { 

    if (managedObjectModel != nil) { 
     return managedObjectModel; 
    } 
    NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"EntryDatabase" ofType:@"momd"]; 
    NSURL *modelURL = [NSURL fileURLWithPath:modelPath]; 
    managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; 

    return managedObjectModel; 
} 

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 

    if((persistentStoreCoordinator != nil)) { 
     return persistentStoreCoordinator; 
    } 

    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]]; 
    NSPersistentStoreCoordinator *psc = persistentStoreCoordinator; 

    // Set up iCloud in another thread: 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     // ** Note: if you adapt this code for your own use, you MUST change this variable: 
     NSString *iCloudEnabledAppID = @"iCloud ID is here, i removed it from stack overflow"; 

     // ** Note: if you adapt this code for your own use, you should change this variable: 
     NSString *dataFileName = @"CoreDataStore.sqlite"; 

     // ** Note: For basic usage you shouldn't need to change anything else 

     NSString *iCloudDataDirectoryName = @"Data.nosync"; 
     NSString *iCloudLogsDirectoryName = @"Logs"; 
     NSFileManager *fileManager = [NSFileManager defaultManager]; 

     NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:dataFileName]; 

     NSURL *localStore = [NSURL fileURLWithPath:storePath]; 

     NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil]; 

     if (iCloud) { 

      NSLog(@"iCloud is working"); 

      NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]]; 

      NSLog(@"iCloudEnabledAppID = %@",iCloudEnabledAppID); 
      NSLog(@"dataFileName = %@", dataFileName); 
      NSLog(@"iCloudDataDirectoryName = %@", iCloudDataDirectoryName); 
      NSLog(@"iCloudLogsDirectoryName = %@", iCloudLogsDirectoryName); 
      NSLog(@"iCloud = %@", iCloud); 
      NSLog(@"iCloudLogsPath = %@", iCloudLogsPath); 

      if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) { 
       NSError *fileSystemError; 
       [fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName] 
         withIntermediateDirectories:YES 
             attributes:nil 
              error:&fileSystemError]; 
       if(fileSystemError != nil) { 
        NSLog(@"Error creating database directory %@", fileSystemError); 
       } 
      } 

      NSString *iCloudData = [[[iCloud path] 
            stringByAppendingPathComponent:iCloudDataDirectoryName] 
            stringByAppendingPathComponent:dataFileName]; 

      NSLog(@"iCloudData = %@", iCloudData); 

      NSMutableDictionary *options = [NSMutableDictionary dictionary]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption]; 
      [options setObject:iCloudEnabledAppID   forKey:NSPersistentStoreUbiquitousContentNameKey]; 
      [options setObject:iCloudLogsPath    forKey:NSPersistentStoreUbiquitousContentURLKey]; 

      [psc lock]; 

      [psc addPersistentStoreWithType:NSSQLiteStoreType 
           configuration:nil 
             URL:[NSURL fileURLWithPath:iCloudData] 
            options:options 
             error:nil]; 

      [psc unlock]; 
     } 
     else { 
      NSLog(@"iCloud is NOT working - using a local store"); 
      NSMutableDictionary *options = [NSMutableDictionary dictionary]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption]; 
      [options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption]; 

      [psc lock]; 

      [psc addPersistentStoreWithType:NSSQLiteStoreType 
           configuration:nil 
             URL:localStore 
            options:options 
             error:nil]; 
      [psc unlock]; 

     } 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      [[NSNotificationCenter defaultCenter] postNotificationName:@"SomethingChanged" object:self userInfo:nil]; 
     }); 
    }); 

    return persistentStoreCoordinator; 

} 
+0

Ensembles(http://ensembles.io)是我開發的用於同步Core Data的框架。它可以讓您控制何時進行同步,還可以自動遷移和合並現有數據。 –

回答

2

據我所知,這不可能發生。反正沒有任何簡單而有效的方式。

http://developer.apple.com/library/mac/#documentation/General/Conceptual/iCloudDesignGuide/Chapters/iCloudFundametals.html

的問題是,iCloud中的操作不透明的。因此iOS決定何時會發生同步以及發生的頻率。在上面的文檔中,Apple表示「最佳做法」是專門使用沙箱或iCloud,但不要在它們之間複製數據。

也就是說,當iCloud變得不可用時,蘋果會提及操作。這似乎符合你的建議。基本上,您需要按照正常方式進行設置,確保您擁有所需的數據,然後停用iCloud並將數據移動到沙箱以處理它。當你想同步時,你只需要複製數據。

要處理iCloud可用性的變化,請實施在接收NSUbiquityIdentityDidChangeNotification通知時調用的方法。您的方法需要執行以下工作:

調用ubiquityIdentityToken方法並存儲其返回值。 將新值與以前的值進行比較,以確定用戶是否退出其帳戶或登錄到其他帳戶。 如果以前使用的帳戶現在不可用,請根據需要在本地保存當前狀態,清空與iCloud相關的數據高速緩存,並刷新所有與iCloud相關的用戶界面元素。 如果您希望允許用戶在iCloud不可用時繼續創建內容,請將該內容存儲在應用的沙箱容器中。當該帳戶再次可用時,將新內容移至iCloud。通常最好不要通知用戶或要求用戶進行任何交互。

這似乎符合您的要求。但是,我只是自己到了這個階段,所以我不能進一步評論。