핵심 데이터 배경 컨텍스트 모범 사례


81

핵심 데이터로 수행해야하는 큰 가져 오기 작업이 있습니다.
내 핵심 데이터 모델이 다음과 같다고 가정 해 보겠습니다.

Car
----
identifier 
type

내 서버에서 자동차 정보 JSON 목록을 가져온 다음 핵심 데이터 Car개체 와 동기화하고 싶습니다 . 즉
, 새 자동차 인 경우-> Car새 정보에서 새 Core Data 개체를 만듭니다 .
자동차가 이미있는 경우-> Core Data Car개체를 업데이트 합니다.

따라서 UI를 차단하지 않고 백그라운드에서이 가져 오기를 수행하고 사용하는 동안 모든 자동차를 표시하는 자동차 테이블보기를 스크롤합니다.

현재 나는 다음과 같이하고있다.

// create background context
NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[bgContext setParentContext:self.mainContext];

[bgContext performBlock:^{
    NSArray *newCarsInfo = [self fetchNewCarInfoFromServer]; 

    // import the new data to Core Data...
    // I'm trying to do an efficient import here,
    // with few fetches as I can, and in batches
    for (... num of batches ...) {

        // do batch import...

        // save bg context in the end of each batch
        [bgContext save:&error];
    }

    // when all import batches are over I call save on the main context

    // save
    NSError *error = nil;
    [self.mainContext save:&error];
}];

하지만 제가 여기서 옳은 일을하고 있는지 잘 모르겠습니다. 예를 들면 다음과 같습니다.

내가 사용해도 setParentContext되나요?
나는 이것을 사용하는 몇 가지 예를 보았지만을 호출하지 않는 다른 예를 보았습니다 setParentContext. 대신 다음과 같은 작업을 수행합니다.

NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
bgContext.persistentStoreCoordinator = self.mainContext.persistentStoreCoordinator;  
bgContext.undoManager = nil;

내가 확실하지 않은 또 다른 점은 주 컨텍스트에서 언제 save를 호출해야하는지입니다. 내 예에서는 가져 오기가 끝날 때 save를 호출하지만 다음을 사용하는 예를 보았습니다.

[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification* note) {
    NSManagedObjectContext *moc = self.managedObjectContext;
    if (note.object != moc) {
        [moc performBlock:^(){
            [moc mergeChangesFromContextDidSaveNotification:note];
        }];
    }
}];  

이전에 언급했듯이 업데이트하는 동안 사용자가 데이터와 상호 작용할 수 있기를 원하는데, 가져 오기가 동일한 차를 변경하는 동안 사용자가 차 유형을 변경하면 어떻게 작성합니까?

최신 정보:

@TheBasicMind의 훌륭한 설명 덕분에 옵션 A를 구현하려고하므로 코드는 다음과 같습니다.

다음은 AppDelegate의 핵심 데이터 구성입니다.

AppDelegate.m  

#pragma mark - Core Data stack

- (void)saveContext {
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            DDLogError(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}  

// main
- (NSManagedObjectContext *)managedObjectContext {
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    _managedObjectContext.parentContext = [self saveManagedObjectContext];

    return _managedObjectContext;
}

// save context, parent of main context
- (NSManagedObjectContext *)saveManagedObjectContext {
    if (_writerManagedObjectContext != nil) {
        return _writerManagedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _writerManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        [_writerManagedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _writerManagedObjectContext;
}  

그리고 이것은 내 가져 오기 방법이 이제 어떻게 생겼는지입니다.

- (void)import {
    NSManagedObjectContext *saveObjectContext = [AppDelegate saveManagedObjectContext];

    // create background context
    NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    bgContext.parentContext = saveObjectContext;

    [bgContext performBlock:^{
        NSArray *newCarsInfo = [self fetchNewCarInfoFromServer];

        // import the new data to Core Data...
        // I'm trying to do an efficient import here,
        // with few fetches as I can, and in batches
        for (... num of batches ...) {

            // do batch import...

            // save bg context in the end of each batch
            [bgContext save:&error];
        }

        // no call here for main save...
        // instead use NSManagedObjectContextDidSaveNotification to merge changes
    }];
}  

그리고 다음과 같은 관찰자가 있습니다.

[[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:nil usingBlock:^(NSNotification* note) {

    NSManagedObjectContext *mainContext = self.managedObjectContext;
    NSManagedObjectContext *otherMoc = note.object;

    if (otherMoc.persistentStoreCoordinator == mainContext.persistentStoreCoordinator) {
        if (otherMoc != mainContext) {
            [mainContext performBlock:^(){
                [mainContext mergeChangesFromContextDidSaveNotification:note];
            }];
        }
    }
}];

부모-자식 모델을 사용하는 경우 데이터베이스를 올바르게 업데이트하려면 자식을 저장 한 다음 부모를 저장해야합니다.
carloabelli

이것은 내 질문의 일부입니다. 이런 종류의 작업에 부모-자식 모델을 사용해야합니까? 다른 옵션은 무엇입니까?
Eyal

1
당신은 당신이 그에게 도움이됩니다이 게시물에 방문해야 raywenderlich.com/15916/...을
훌리오 몬토야

1
@ cabellicar123 왜? : 동시성 : 코어 데이터 프로그래밍 가이드에서 Once all of the data has been consumed and turned into NSManagedObject instances, you call save on the private context, which moves all of the changes into the main queue context without blocking the main queue. developer.apple.com/library/ios/documentation/Cocoa/Conceptual/...
디마 Deplov

@Eyal "여기서 효율적으로 가져 오기를 시도하고 있습니다"어떤가요?
Said

답변:


187

이것은 처음으로 Core Data에 접근하는 사람들에게 매우 혼란스러운 주제입니다. 가볍게 말하지는 않지만 경험을 통해 Apple 문서가이 문제에 대해 다소 오해의 소지가 있다고 확신합니다. 많은 경우에 부모 / 자식 컨텍스트에 의존하고 단순히 자식에서 부모로 저장하는 것보다 더 나은 솔루션).

문서는 부모 / 자식 컨텍스트가 백그라운드 처리를 수행하는 새로운 선호 방법이라는 강한 인상을줍니다. 그러나 Apple은 몇 가지 강력한 경고를 강조하지 않습니다. 첫째, 자식 컨텍스트로 가져 오는 모든 것은 먼저 부모를 통해 가져옵니다. 따라서 기본 스레드에서 실행되는 기본 컨텍스트의 자식을 기본 스레드의 UI에 이미 표시된 데이터 처리 (편집)로 제한하는 것이 가장 좋습니다. 일반적인 동기화 작업에 사용하는 경우 현재 UI에 표시되는 범위를 훨씬 넘어서는 데이터를 처리하기를 원할 것입니다. NSPrivateQueueConcurrencyType을 사용하더라도 하위 편집 컨텍스트의 경우 잠재적으로 주 컨텍스트를 통해 많은 양의 데이터를 끌어와 성능 저하 및 차단으로 이어질 수 있습니다. 이제 기본 컨텍스트를 동기화에 사용하는 컨텍스트의 하위로 만들지 않는 것이 가장 좋습니다. 수동으로 수행하지 않는 한 동기화 업데이트에 대한 알림을받지 않고 잠재적으로 오래 실행되는 작업을 기본 컨텍스트의 하위 인 편집 컨텍스트에서 기본 연락처를 통해 데이터 저장소까지 계단식으로 시작된 저장에 응답해야 할 수 있습니다. 데이터를 수동으로 병합하고 기본 컨텍스트에서 무효화해야하는 항목을 추적하고 다시 동기화해야합니다. 가장 쉬운 패턴은 아닙니다. 또한 기본 컨텍스트의 하위 인 편집 컨텍스트에서 기본 연락처를 통해 데이터 저장소까지 계단식으로 시작된 저장에 응답해야 할 수있는 컨텍스트에서 잠재적으로 오래 실행되는 작업을 실행하게됩니다. 데이터를 수동으로 병합하고 기본 컨텍스트에서 무효화해야하는 항목을 추적하고 다시 동기화해야합니다. 가장 쉬운 패턴은 아닙니다. 또한 기본 컨텍스트의 하위 인 편집 컨텍스트에서 기본 연락처를 통해 데이터 저장소까지 계단식으로 시작된 저장에 응답해야 할 수있는 컨텍스트에서 잠재적으로 오래 실행되는 작업을 실행하게됩니다. 데이터를 수동으로 병합하고 기본 컨텍스트에서 무효화해야하는 항목을 추적하고 다시 동기화해야합니다. 가장 쉬운 패턴은 아닙니다.

Apple 문서에서 명확하지 않은 것은 작업을 수행하는 "오래된"스레드 제한 방식과 작업을 수행하는 새로운 부모-자식 컨텍스트 방식을 설명하는 페이지에 설명 된 기술의 혼합이 필요할 가능성이 가장 높다는 것입니다.

가장 좋은 방법은 NSPrivateQueueConcurrencyType 저장 컨텍스트를 최상위 상위 항목으로 사용하여 데이터 저장소에 직접 저장하는 것입니다 (여기서는 일반적인 솔루션을 제공하고 있으며 최상의 솔루션은 세부 요구 사항에 따라 달라질 수 있음). [편집 : 당신은이 맥락에서 그다지 직접적으로하지 않을 것입니다] 그런 다음 그 저장 맥락에 적어도 두 명의 직접적인 자식을 제공하십시오. UI에 사용하는 NSMainQueueConcurrencyType 기본 컨텍스트 중 하나는 [편집 :이 컨텍스트에서 데이터를 편집하지 않는 것이 가장 좋습니다], 다른 하나는 NSPrivateQueueConcurrencyType, 데이터의 사용자 편집을 수행하는 데 사용합니다. 첨부 된 다이어그램의 옵션 A) 동기화 작업.

그런 다음 기본 컨텍스트를 동기화 컨텍스트에 의해 생성 된 NSManagedObjectContextDidSave 알림의 대상으로 만들고 알림 .userInfo 사전을 기본 컨텍스트의 mergeChangesFromContextDidSaveNotification :으로 보냅니다.

고려해야 할 다음 질문은 사용자 편집 컨텍스트 (사용자가 편집 한 내용이 인터페이스에 다시 반영되는 컨텍스트)를 넣는 위치입니다. 사용자의 작업이 항상 소량의 제시된 데이터에 대한 편집으로 제한되는 경우 NSPrivateQueueConcurrencyType을 사용하여이를 다시 기본 컨텍스트의 하위로 만드는 것이 최선의 방법이며 관리하기 가장 쉽습니다 (저장하면 편집 내용을 기본 컨텍스트에 직접 저장하고 NSFetchedResultsController가 있으면 적절한 대리자 메서드가 자동으로 호출되어 UI가 업데이트를 처리 할 수 ​​있습니다. controller : didChangeObject : atIndexPath : forChangeType : newIndexPath :) (다시 옵션 A).

반면에 사용자 작업으로 인해 많은 양의 데이터가 처리 될 수있는 경우 저장 컨텍스트에 세 개의 직접 하위 항목이 있도록 기본 컨텍스트 및 동기화 컨텍스트의 다른 피어로 만드는 것을 고려할 수 있습니다. main , sync (비공개 대기열 유형) 및 편집 (비공개 대기열 유형). 이 배열을 다이어그램의 옵션 B로 표시했습니다.

동기화 컨텍스트와 유사하게 데이터가 저장 될 때 (또는 더 세분화가 필요한 경우 데이터가 업데이트 될 때) [편집 : 알림을 수신하도록 기본 컨텍스트를 구성]하고 데이터를 병합하는 조치를 취해야합니다 (일반적으로 mergeChangesFromContextDidSaveNotification 사용 : ). 이 배열을 사용하면 주 컨텍스트가 save : 메소드를 호출 할 필요가 없습니다. 여기에 이미지 설명 입력

상위 / 하위 관계를 이해하려면 옵션 A를 선택하십시오. 상위 하위 접근 방식은 단순히 편집 컨텍스트가 NSManagedObject를 가져 오면 먼저 저장 컨텍스트, 다음으로 기본 컨텍스트, 마지막으로 컨텍스트 편집에 "복사"(등록)된다는 의미입니다. 변경 사항을 적용 할 수 있으며 save :를 호출하면 편집 컨텍스트에서 변경 사항이 기본 컨텍스트에만 저장 됩니다 . 기본 컨텍스트에서 save :를 호출 한 다음 저장 컨텍스트에서 save :를 호출해야 디스크에 기록됩니다.

자식에서 부모까지 저장하면 다양한 NSManagedObject 변경 및 저장 알림이 실행됩니다. 예를 들어 결과 가져 오기 컨트롤러를 사용하여 UI에 대한 데이터를 관리하는 경우 대리자 메서드가 호출되어 적절하게 UI를 업데이트 할 수 있습니다.

몇 가지 결과 : 편집 컨텍스트에서 개체 및 NSManagedObject A를 가져온 다음 수정하고 저장하면 수정 사항이 기본 컨텍스트로 반환됩니다. 이제 기본 및 편집 컨텍스트에 대해 수정 된 개체가 등록되었습니다. 그렇게하는 것은 나쁜 스타일이지만, 이제 주 컨텍스트에서 개체를 다시 수정할 수 있으며 이제 편집 컨텍스트에 저장되므로 개체와 달라집니다. 그런 다음 편집 컨텍스트에 저장된대로 개체를 추가로 수정하려고하면 수정 내용이 기본 컨텍스트의 개체와 동기화되지 않으며 편집 컨텍스트를 저장하려고하면 오류가 발생합니다.

이러한 이유로 옵션 A와 같은 배열을 사용하면 개체를 가져오고, 수정하고, 저장하고, 편집 컨텍스트를 재설정하는 것이 좋습니다 (예 : [editContext reset]). 주어진 블록이 [editContext performBlock :])에 전달됩니다. 또한 규칙을 정하고 주 컨텍스트에 대한 편집을 피하는 것이 가장 좋습니다 . 또한 다시 반복하는 것이 좋습니다. 편집 컨텍스트에 대한 많은 개체, 기본 컨텍스트는 기본 스레드 에서 가져 오기 처리 수행합니다.이러한 객체는 부모에서 자식 컨텍스트로 반복적으로 복사됩니다. 처리중인 데이터가 많은 경우 UI에서 응답하지 않을 수 있습니다. 예를 들어 관리되는 개체의 큰 저장소가 있고 모든 개체를 편집 할 수있는 UI 옵션이있는 경우입니다. 이 경우 옵션 A와 같이 앱을 구성하는 것은 좋지 않습니다.이 경우 옵션 B가 더 나은 방법입니다.

수천 개의 개체를 처리하지 않는 경우 옵션 A로 충분할 수 있습니다.

BTW는 어떤 옵션을 선택하는지 너무 걱정하지 마십시오. A로 시작하고 B로 변경해야하는 경우 좋은 생각 일 수 있습니다. 이러한 변경은 생각보다 쉽고 일반적으로 예상보다 결과가 적습니다.


자세한 답변에 감사드립니다 (+1). 제 개발 단계에서 이러한 추가 컨텍스트를 추가하는 것은 큰 변화가 될 것입니다. 이 백그라운드 작업을 수행하고 가능한 한 간단하게 유지하기 위해 하나의 추가 컨텍스트 만 사용하고 싶습니다. 나는 여전히 부모-자녀 접근법과 다른 대안 사이의 차이점을 얻지 못합니다. 내 예제 코드를 가져 와서 내가했던 잘못된 단계를 고칠 수 있다면 고맙게 생각합니다.
Eyal 2014-07-10

옵션 A를 사용합니다. 부모 자식 접근 방식은 편집 컨텍스트가 NSManagedObjects를 가져 오면 먼저 저장 컨텍스트, 다음으로 주 컨텍스트, 마지막으로 컨텍스트 편집에 "복사"(등록)된다는 것을 의미합니다. 변경 사항을 적용한 다음 save를 호출하면 편집 컨텍스트에서 변경 사항이 기본 컨텍스트에만 저장 됩니다 . 기본 컨텍스트에서 save :를 호출 한 다음 save :를 호출해야 디스크에 기록됩니다. 내 응답을 수정하겠습니다.
TheBasicMind

3
여기에 답 해주셔서 기쁩니다. 귀하의 정보는 귀중합니다. 나는 이것을 시도하기 위해 더 많은 자신감을 얻었다 고 생각한다. 나는 단지 내 머릿속에있는이 모든 훌륭한 정보를 주문해야한다. 편집 컨텍스트가 약간 혼란 스럽습니다. 다른 배경 컨텍스트와의 차이점은 무엇입니까? 왜 그는 아이이고 동기화 컨텍스트는 그렇지 않습니까? 어쨌든 지금은 사용자 편집을 위해 별도의 컨텍스트를 사용하지 않을 것이라고 생각합니다. 사용자는 한 번에 하나의 항목 (Car) 만 삭제하거나 한 번에 하나씩 속성을 변경할 수 있기 때문에 기본 컨텍스트로 각 편집을 수행하고 직접 호출합니다. 저장 : 그것에.
Eyal

또한 옵션 A를 구현하기 위해 작성한 새로운 코드로 질문을 업데이트했습니다 (Edit context child 제외). 괜찮은지 확인해 주시겠습니까? save : on the Save 컨텍스트 어디서나 호출해야하는지 잘 모르겠습니다. 아니면 알림의 변경 사항을 병합하는 것으로 충분합니까?
Eyal

@TheBasicMind "저장"컨텍스트를 저장할 시간은 언제입니까? 사용자 상호 작용과 독립적으로 수행합니까?
ctietze

15

첫째, 부모 / 자식 컨텍스트는 백그라운드 처리 용이 아닙니다. 여러 뷰 컨트롤러에서 생성 될 수있는 관련 데이터의 원자 적 업데이트를위한 것입니다. 따라서 마지막 뷰 컨트롤러가 취소되면 부모에 부정적인 영향을주지 않고 자식 컨텍스트를 버릴 수 있습니다. 이것은 [^ 1]에서이 답변의 맨 아래에있는 Apple에 의해 완전히 설명됩니다. 이제는 불가능하고 일반적인 실수에 빠지지 않았으므로 백그라운드 코어 데이터를 올바르게 수행하는 방법에 집중할 수 있습니다.

새 영구 저장소 코디네이터 (iOS 10에서는 더 이상 필요하지 않음, 아래 업데이트 참조) 및 개인 대기열 컨텍스트를 만듭니다. 저장 알림을 듣고 변경 사항을 기본 컨텍스트에 병합합니다 (iOS 10에서는 컨텍스트에이를 자동으로 수행하는 속성이 있음).

Apple의 샘플은 "Earthquakes : 백그라운드 대기열을 사용하여 핵심 데이터 저장소 채우기" https://developer.apple.com/library/mac/samplecode/Earthquakes/Introduction/Intro.html 을 참조하십시오. 개정 내역에서 볼 수 있습니다. 2014-08-19에 그들은 "백그라운드 큐에서 데이터를 가져 오기 위해 두 번째 코어 데이터 스택을 사용하는 방법을 보여주는 새로운 샘플 코드"를 추가했습니다.

다음은 AAPLCoreDataStackManager.m의 비트입니다.

// Creates a new Core Data stack and returns a managed object context associated with a private queue.
- (NSManagedObjectContext *)createPrivateQueueContext:(NSError * __autoreleasing *)error {

    // It uses the same store and model, but a new persistent store coordinator and context.
    NSPersistentStoreCoordinator *localCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[AAPLCoreDataStackManager sharedManager].managedObjectModel];

    if (![localCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil
                                                  URL:[AAPLCoreDataStackManager sharedManager].storeURL
                                              options:nil
                                                error:error]) {
        return nil;
    }

    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [context performBlockAndWait:^{
        [context setPersistentStoreCoordinator:localCoordinator];

        // Avoid using default merge policy in multi-threading environment:
        // when we delete (and save) a record in one context,
        // and try to save edits on the same record in the other context before merging the changes,
        // an exception will be thrown because Core Data by default uses NSErrorMergePolicy.
        // Setting a reasonable mergePolicy is a good practice to avoid that kind of exception.
        context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;

        // In OS X, a context provides an undo manager by default
        // Disable it for performance benefit
        context.undoManager = nil;
    }];
    return context;
}

그리고 AAPLQuakesViewController.m에서

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

    if (notification.object != self.managedObjectContext) {

        [self.managedObjectContext performBlock:^{
            [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
        }];
    }
}

다음은 샘플 설계 방법에 대한 전체 설명입니다.

지진 : "개인"영구 저장소 코디네이터를 사용하여 백그라운드에서 데이터 가져 오기

Core Data를 사용하는 대부분의 응용 프로그램은 단일 영구 저장소 조정자를 사용하여 주어진 영구 저장소에 대한 액세스를 중재합니다. Earthquakes는 원격 서버에서 검색된 데이터를 사용하여 관리 대상 개체를 만들 때 추가 "개인"영구 저장소 코디네이터를 사용하는 방법을 보여줍니다.

애플리케이션 아키텍처

응용 프로그램은 두 개의 핵심 데이터 "스택"(영구적 저장소 조정자의 존재에 의해 정의 됨)을 사용합니다. 첫 번째는 일반적인 "범용"스택입니다. 두 번째는 원격 서버에서 데이터를 가져 오기 위해 특별히 뷰 컨트롤러에 의해 생성됩니다 (iOS 10부터는 두 번째 코디네이터가 더 이상 필요하지 않습니다. 답변 하단의 업데이트 참조).

기본 영구 저장소 코디네이터는 단일 "스택 컨트롤러"개체 (CoreDataStackManager의 인스턴스)에 의해 판매됩니다. 코디네이터 [^ 1]와 함께 작동 할 관리 개체 컨텍스트를 만드는 것은 클라이언트의 책임입니다. 스택 컨트롤러는 응용 프로그램에서 사용하는 관리 개체 모델과 영구 저장소의 위치에 대한 속성도 제공합니다. 클라이언트는 이러한 후자의 속성을 사용하여 기본 코디네이터와 병렬로 작업 할 추가 영구 저장소 코디네이터를 설정할 수 있습니다.

QuakesViewController의 인스턴스 인 메인 뷰 컨트롤러는 스택 컨트롤러의 영구 저장소 코디네이터를 사용하여 영구 저장소에서 지진을 가져와 테이블 뷰에 표시합니다. 서버에서 데이터를 검색하는 것은 서버에서 검색된 레코드가 새로운 지진인지 기존 지진에 대한 잠재적 인 업데이트인지 확인하기 위해 영구 저장소와 상당한 상호 작용이 필요한 장기 실행 작업 일 수 있습니다. 이 작업 중에 애플리케이션이 응답을 유지할 수 있도록 뷰 컨트롤러는 두 번째 코디네이터를 사용하여 영구 저장소와의 상호 작용을 관리합니다. 스택 컨트롤러에서 판매하는 기본 코디네이터와 동일한 관리 개체 모델 및 영구 저장소를 사용하도록 코디네이터를 구성합니다.

[^ 1] : 이는 특히 iOS 애플리케이션에서 컨텍스트가 한 뷰 컨트롤러에서 다른 뷰 컨트롤러로 전달되는 "배턴 전달"접근 방식을 지원합니다. 루트 뷰 컨트롤러는 초기 컨텍스트를 만들고 필요할 때 자식 뷰 컨트롤러에 전달하는 역할을합니다.

이 패턴의 이유는 관리 개체 그래프의 변경 사항이 적절하게 제한되도록하기위한 것입니다. Core Data는 독립적이고 취소 가능한 변경 세트를 쉽게 지원할 수있는 유연한 아키텍처를 허용하는 "중첩 된"관리 객체 컨텍스트를 지원합니다. 하위 컨텍스트를 사용하면 사용자가 관리 대상 개체를 변경 한 다음 단일 트랜잭션으로 상위에 전체적으로 커밋 (그리고 궁극적으로 저장소에 저장)하거나 삭제할 수 있도록 허용 할 수 있습니다. 애플리케이션의 모든 부분이 단순히 애플리케이션 델리게이트에서 동일한 컨텍스트를 검색하는 경우이 동작을 지원하기 어렵거나 불가능하게 만듭니다.

업데이트 : iOS 10에서 Apple은 동기화를 sqlite 파일 수준에서 영구 코디네이터로 이동했습니다. 이것은 이제 개인 큐 컨텍스트를 만들고 이전에 그렇게했을 때와 동일한 성능 문제없이 기본 컨텍스트에서 사용하는 기존 코디네이터를 재사용 할 수 있음을 의미합니다.


7

그런데이 애플 문서 는이 문제를 매우 명확하게 설명하고 있습니다. 관심있는 사람을위한 위의 Swift 버전

let jsonArray = … //JSON data to be imported into Core Data
let moc = … //Our primary context on the main queue

let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMOC.parentContext = moc

privateMOC.performBlock {
    for jsonObject in jsonArray {
        let mo = … //Managed object that matches the incoming JSON structure
        //update MO with data from the dictionary
    }
    do {
        try privateMOC.save()
        moc.performBlockAndWait {
            do {
                try moc.save()
            } catch {
                fatalError("Failure to save context: \(error)")
            }
        }
    } catch {
        fatalError("Failure to save context: \(error)")
    }
}

iOS 10 이상용 NSPersistentContainer 를 사용하는 경우 더 간단합니다.

let jsonArray = …
let container = self.persistentContainer
container.performBackgroundTask() { (context) in
    for jsonObject in jsonArray {
        let mo = CarMO(context: context)
        mo.populateFromJSON(jsonObject)
    }
    do {
        try context.save()
    } catch {
        fatalError("Failure to save context: \(error)")
    }
}

데이터를 가져 오는 방법을 가져올 때 무작위로 충돌이 발생하고 때로는 제대로 작동하기 때문에 데이터를 가져 오는 방법에 대한 예를 들어 주시겠습니까? @hariszaman
Parth Barot

그것은 당신이 수정하고 동시에 컨텍스트 저장하는 동안 수 있습니다
hariszaman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.