2011-01-27 5 views
3

미리 도움을 청하십시오. 나는 오늘 이것을 보냈으며 프레임 워크가 어떻게 작동하는지에 대한 나의 이해에 심각하게 잘못된 것이 있다고 생각합니다.NSManagedObjectContext를 'clean'으로 저장할 때 병합 오류가 발생하는 이유는 무엇입니까?

엔티티에 부모/자식 관계가있는 핵심 데이터 응용 프로그램을 만들고 있습니다. 응용 프로그램은 시작할 때 NSManagedObjectContext (MOC)를 만듭니다. 응용 프로그램을 처음 실행하면 비동기 블록을 사용하여 plist의 내용을 두 번째 MOC로 가져옵니다 (루트 노드는 URI 및 -managedObjectIDForURIRepresentation을 사용하여 주 MOC에서 가져옵니다). 블록 완료 직전입니다. 두 번째 컨텍스트를 저장합니다. 이 코드에 전성 검사를 수행하고 충분히 확인했습니다

- (void)backgroundContextDidSave:(NSNotification *)notification { 
    if(![notification.object isEqual:self.managedObjectContext]){ 
     if (![NSThread isMainThread]) { 
      [self performSelectorOnMainThread:@selector(backgroundContextDidSave:) 
            withObject:notification 
           waitUntilDone:NO]; 
      return; 
    }  
     [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];  ; 
    } 
} 

, 두 번째 MOC가 저장할 때 : 내 데이터 컨트롤러에서

나는 다음과 같은 코드가 통지를 보낼 때 실행되는 NSManagedObjectContextDidSaveNotification에 가입 , 이것은 블록을 실행하는 스레드에서 호출되고, 지연되며, 주 스레드에서 실행됩니다. 알림 개체에는 두 번째 MOC에서 가져온 모든 개체가 포함됩니다. 두 개체는 다음에 처리 할 두 개체를 포함합니다.

TreeEntry *oldParent=self.parent; //keep a pointer to the old parent around so we can delete self from the children 

// These next four lines are a sanity check to make sure that both objects are on the same MOC we're saving 
NSManagedObjectContext *selfContext=self.managedObjectContext; 
NSManagedObjectContext *parentContext=self.parent.managedObjectContext; 
NSManagedObjectContext *sharedContext=[[DataController sharedDataController] managedObjectContext]; 
assert([selfContext isEqual:parentContext] && [selfContext isEqual:sharedContext]); 

// now we fault the two objects to make sure we can not possibly have them or any changes 
// to them in the state of the main MOC, by this time the second MOC is long gone 
[sharedContext refreshObject:self.parent mergeChanges:NO]; 
[sharedContext refreshObject:self mergeChanges:NO]; 

// up to this point, sharedContex.insertedObjects, sharedContext.updatedObects and sharedContext.deletedObjects 
// have all contained no objects at all. None of the above was necessary as the MOC held no changes at all 
[sharedContext saveChanges]; // we save it to, well, just to make sure I guess, I may be going crazy 

// Now we carry out two changes to the objects, problem occurs if only one change is carried out, 
// I'm showing both to show that there relationship is being kept consistent and valid 
self.parent=nil; 
[oldParent removeChild:self]; 


// When the next line is run the save fails with a merge conflict 
[sharedContext saveChanges]; 

마지막 저장 실패 : 이것은 내가 개체가, 단순히 그 부모로부터 아이를 제거하기위한 것입니다 속한 서브 클래스 NSManagedObject하는 방법에 다음 코드를 실행 완료

병합 실패 인 Cocoa 오류 133020이 발생합니다. 오류의 두 NSMergeConflict는 처리중인 항목 (self 및 self.parent)과 관련됩니다.

나는 그것이 어떻게 될 수 있는지 이해하지 못합니다. 개체는 수정 될 때 상태가 없으므로 저장소에서로드해야합니다. 두 가지 간단한 변경이 이루어지며 이후에 곧바로 저장되면 병합 충돌이 발생합니다. 어떻게 그렇게 될수 있니? 그 밖의 어떤 것도 상점을 망쳐 놓은 것이 아니며 방금 그 물건을로드했습니다.

병합 정책을 변경할 수는 있지만 상황을 이해하지 않고는 수행하고 싶지 않습니다.

아이디어가 있으십니까? 나는 무슨 일이 일어나고 있는지 내 정신 모델이 잘못되었다고 확신하지만 하루 종일 바르게 설정할 수는 없었다!

+0

관리 객체 모델에서 부모/자식에 대해 반대 관계를 설정 했습니까? 동일한 작업을 두 번 수행하면 더 이상 관계가없는 객체로 removeChild :를 호출하여 관리되는 objet 컨텍스트를 혼동시킬 수 있습니다. 정말 깨끗한 컨텍스트를 원한다면 refreshObject뿐 아니라 NSManagedObjectContext를 사용해야합니다. – ImHuntingWabbits

+0

Wabbits, 답장을 보내 주셔서 감사합니다. 예, 역 관계가 설정되어 있고 어제까지는 'self.parent = nil'행만 제거를 수행했습니다.어떤 이유로 든 올바르게 전파되지 않는 경우를 대비하여 부모 측만 추가 했으므로 코드 샘플에이 코드를 그대로 두어 독자가 병합 오류가 일치하지 않는 관계로 인해 발생했다고 생각하지 않도록했습니다. '재설정'메시지가 너무 심한데 문제가 무엇인지 이해하고 싶습니다. – oldbeamer

답변

7

좋아요, 프레임 워크가 작동하는 방식이나 더 정확한 NSManagedStoreCoordinator 캐시에 대한 근본적인 오해가있었습니다.

배경 컨텍스트를 저장하면 변경 내용이 디스크로 이동하지만 NSManagedStoreCoordinator (두 컨텍스트 모두 공유)는 캐시를 업데이트하거나 무효화합니다.

주 MOC에서 개체를 새로 고칠 때 개체를 다시 채우는 데 사용 된 데이터는 이전 데이터가있는 캐시에서 가져옵니다. 디스크에서 다시로드하지 않습니다. 해결책은 [MOC setStalenessInterval : 0.0]을 사용하여 강제로 디스크에서 로딩하는 것입니다.

관련 문제