2017-12-17 1 views
0

iCloud를 백엔드로 사용하여 Ensembles 프레임 워크를 통합하려는 Core Data 어플리케이션이 있습니다. 하나의 장치에서 변경 작업을 수행 할 때 원격 변경 사항을 적용하기 위해 다른 장치의 컨텍스트를 변경하고 컨텍스트를 저장해야한다는 점을 제외하고 대부분의 작업이 작동합니다.앙상블과 코어 데이터 동기화 : 로컬 모델이 변경 될 때까지 원격 변경 사항이 취소되지 않습니다.

데이터를 반영한 ​​테이블 뷰는 NSFetchedResultsControllerDelegate을 따릅니다. 로컬 데이터가 변경되어 원격 변경 사항을 선택하면 원격 변경 사항이 올바르게 반영됩니다.

syncWithCompletion (아래)을 수동으로 호출하는 "동기화"버튼을 구현해도 변경 사항이 적용되지 않습니다.

syncWithCompletion을 호출하는 2 분마다 실행되는 타이머가 변경 사항을 적용하지 않습니다.

동기화를 껐다가 다시 켜면 변경 사항이 적용됩니다.

앱을 다시 시작해도 변경 사항이 적용되지 않습니다.

#pragma mark - ENSEMBLES 

- (void)setupEnsembles { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 

    // set the sync UI on 
    [[NSNotificationCenter defaultCenter] postNotificationName:@"setSyncUIOn" object:nil]; 

    // setup ensemble 
    self.cloudFileSystem = [[CDEICloudFileSystem alloc] initWithUbiquityContainerIdentifier:nil]; 
    self.ensemble = [[CDEPersistentStoreEnsemble alloc] initWithEnsembleIdentifier:@"RecordStore" 
                   persistentStoreURL:self.storeURL 
                  managedObjectModelURL:[self modelURL] 
                   cloudFileSystem:self.cloudFileSystem]; 
    self.ensemble.delegate = self; 

    // Listen for local saves, and trigger merges 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(localSaveOccurred:) 
               name:CDEMonitoredManagedObjectContextDidSaveNotification 
              object:nil]; 

    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(cloudDataDidDownload:) 
               name:CDEICloudFileSystemDidDownloadFilesNotification 
              object:nil]; 

    [self syncWithCompletion:NULL]; 

    // configure a timer to trigger a merge every two minutes 
    if (!self.ensemblesSyncTimer) { 
    self.ensemblesSyncTimer = [NSTimer scheduledTimerWithTimeInterval:120.0 
                   target:self 
                  selector:@selector(performScheduledSync:) 
                  userInfo:nil 
                   repeats:YES]; 
    } 
} 

- (void)performScheduledSync:(NSTimer*)aTimer { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 
    [self syncWithCompletion:NULL]; 
} 

- (void)syncWithCompletion:(void(^)(void))completion { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 

    // set the sync UI on 
    [[NSNotificationCenter defaultCenter] postNotificationName:@"setSyncUIOn" object:nil]; 

    // this checks to make sure there is an ensemble, because this method 
    // can be called without knowing whether ensembles is enabled or not 
    if (self.ensemble) { 
    if (coreDataDebug==1) { NSLog(@"there is an ensemble, going to leech or merge"); } 

    if (!self.ensemble.isLeeched) { 
     if (coreDataDebug==1) { NSLog(@"leeching"); } 
     [self.ensemble leechPersistentStoreWithCompletion:^(NSError *error) { 
     if (error) NSLog(@"Error in leech: %@", [error localizedDescription]); 

     // set the last synced date 
     NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
     dateFormatter.timeStyle = NSDateFormatterMediumStyle; 
     dateFormatter.dateStyle = NSDateFormatterMediumStyle; 
     [dateFormatter setLocale:[NSLocale currentLocale]]; 
     [[NSUserDefaults standardUserDefaults] setObject:[dateFormatter stringFromDate:[NSDate date]] 
                forKey:@"iCloudLastSyncDate"]; 

     [[NSNotificationCenter defaultCenter] postNotificationName:@"setSyncUIOff" object:nil]; 
                  object:nil]; 
     if (completion) {completion();} 
     }]; 
    } 
    else { 
     if (coreDataDebug==1) { NSLog(@"merging"); } 
     [self.ensemble mergeWithCompletion:^(NSError *error) { 
     if (error) NSLog(@"Error in merge: %@", [error localizedDescription]); 

     // set the last synced date 
     NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 
     dateFormatter.timeStyle = NSDateFormatterMediumStyle; 
     dateFormatter.dateStyle = NSDateFormatterMediumStyle; 
     [dateFormatter setLocale:[NSLocale currentLocale]]; 
     [[NSUserDefaults standardUserDefaults] setObject:[dateFormatter stringFromDate:[NSDate date]] 
                forKey:@"iCloudLastSyncDate"]; 

     [[NSNotificationCenter defaultCenter] postNotificationName:@"setSyncUIOff" object:nil]; 
     [[NSNotificationCenter defaultCenter] postNotificationName:@"recordCollectionNeedsRefresh" 
                  object:nil]; 
     if (completion) {completion();} 
     }]; 
    } 
    } 
} 

- (void)localSaveOccurred:(NSNotification *)notif { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 
    [self syncWithCompletion:NULL]; 
} 

- (void)cloudDataDidDownload:(NSNotification *)notif { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 
    [self syncWithCompletion:NULL]; 
} 

- (void)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble didSaveMergeChangesWithNotification:(NSNotification *)notification { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 

    [_context performBlockAndWait:^{ 
    [_context mergeChangesFromContextDidSaveNotification:notification]; 
    }]; 
} 

- (NSArray *)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble globalIdentifiersForManagedObjects:(NSArray *)objects { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 
    return [objects valueForKeyPath:@"uniqueIdentifier"]; 
} 

- (void)removeEnsembles { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 
    [self disconnectFromSyncServiceWithCompletion:NULL]; 
} 

- (void)disconnectFromSyncServiceWithCompletion:(CDECodeBlock)completion { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 
    [self.ensemble deleechPersistentStoreWithCompletion:^(NSError *error) { 

    self.ensemble.delegate = nil; 
    [self.ensemble dismantle]; 
    self.ensemble = nil; 
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"iCloudLastSyncDate"]; 
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"iCloudSyncingEnabled"]; 
    [self.ensemblesSyncTimer invalidate]; 
    self.ensemblesSyncTimer = nil; 

    if (completion) completion(); 
    }]; 
} 

- (void)persistentStoreEnsemble:(CDEPersistentStoreEnsemble *)ensemble didDeleechWithError:(NSError *)error { 
    if (ensemblesDataDebug==1) { printf("Running %s\n", [NSStringFromSelector(_cmd) UTF8String]); } 
    NSLog(@"Store did deleech with error: %@", error); 
} 

내가 잘못 가고있는 아이디어가 있습니까?

[편집 내 댓글이 너무 깁니다 이후]

첫째, didSaveMergeChangesWithNotification 내가 할 경우 하지가 호출되는 않는 지방의 저장과 구름의 변화 (그들이 전파 한 가정이있다 -있는 방법에있다 내가 수동 동기화를 시작할 때 전화를 걸지도 않는다. 로컬 모델을 변경 한 다음 컨텍스트를 저장할 때만 호출됩니다. 나는 그것이 내가 어디를 떠나는 지 잘 모른다. 둘째, 가져 오기 컨트롤러를 확인하면 클라우드의 변경 사항이 실제로 제거되지 않습니다. 조사를 계속하기 위해 CDELoggingLevelVerbose을 켰지 만 내가 근본적으로 잘못하고있는 일이 있다는 것을 알고 있습니다.

또한 큰 변화가 있습니다. Ensemble Github의 이전 문제에서 시뮬레이터의 iCloud 동기화가 실제로 작동한다는 것을 깨달았습니다. 불행히도 필자는 어떤 장치도 가지고 있지 않으므로 시뮬레이터에서 모든 테스트를 수행하고 있습니다. 테스트 중에 iPhone에 너무 많은 iCloud 로그인을 기록했습니다. 이게 그럴 수 있니? 실제로 이것이 정상적으로 작동하고 있다고 확신 할 수 있습니까?하지만 시뮬레이터에 실제로 iCloud 동기화 트리거를 보내지 않는 무언가가 있습니까?

+0

두려운 "구름 맞대기"확장 프로그램에 맞으셨습니까? 아니면 "ibutt"라는 맞춤형 백엔드를 만드셨습니까? iCloud 드라이브를 단순히 사용하는 경우 가능한 한 설명하는 것은 단순히 파일을 동기화하는 데 시간이 걸리는 것입니다. 앙상블은 다운로드를 요구하는 것 외에는 영향을 줄 수 없습니다. –

+0

@DrewMcCormack 하, 죄송합니다. 예, "엉덩이 구름"이 설치되었습니다. 질문을 편집 한 후 잠시 후 귀하의 제안에 귀하의 제안을 시험해 보겠습니다. 보통 나는 그 확장이 재미 있다고 느낍니다. 오늘 말고. – user4034838

+0

시뮬레이터에서 테스트 중이라면 실제로 파일을 제대로 다운로드하지 않았을 가능성이 있습니다. 나는 시뮬레이터에 문제가있는 사용자로부터의보고를 들었다. Xcode 디버그 메뉴를 사용하여 파일의 iCloud 동기화를 트리거 할 수 있습니다. Device 또는 Dropbox로 테스트를하지 않은 경우, CloudKit을 사용하는 Ensembles 2 만 제안 할 수 있지만 수수료가 있습니다. iPod touch를 잡을 수 있다면 테스트 용으로 괜찮을 수도 있습니다. –

답변

1

왜 작동하지 않는지는 분명하지 않지만 알아낼 수있는 몇 가지 사항이 있습니다.

먼저 병합 (sync 버튼을 누름)과 반대되는 로컬 저장을 할 때 로그가 다른 것을 파악하십시오. 두 경우 모두 didSaveMergeChangesWithNotification: 대리자 메서드가 트리거됩니까? 클라우드에 변화가 있다고 가정 할 때, 그것은해야합니다.

가져 오기 결과 컨트롤러를 확인해 보는 것도 좋습니다. 변경 사항이 상점에 입력 될 수는 있지만 가져 오기 컨트롤러는 가져 오지 않을 수 있습니다. 한 가지 방법은 performFetch에 전화를 걸어 각 병합 끝에 UI를 다시로드하여 문제가 될 수 있는지 테스트하는 것입니다.

Ensemble이 실제로 데이터를 가져오고 병합하는지 확인하는 또 다른 방법은 자세한 로깅을 설정하는 것입니다. CDESetCurrentLogLevel 함수를 사용하고 CDELoggingLevelVerbose을 전달하십시오. 그러면 프레임 워크가하는 일에 대한 많은 정보가 출력되고 단서를 제공해야합니다.

+0

이것은 시뮬레이터 대신 실제 장치를 사용하여 모두 수정 된 것으로 보입니다. 어깨를 으해라. – user4034838

관련 문제