2014-09-16 4 views
0

다음과 같이 Core Data에 상위 - 하위 - 하위 핵심 데이터 컨텍스트 설정이 있습니다. 나는 손자 컨텍스트에 대한 요청을 페치 실행하려고 할 때마다, 이것은이 교착 상태가 발생 내 코드입니다NSManagedObjectContext - 교착 상태의 원인이되는 하위 컨텍스트

- (NSManagedObjectContext *)defaultPrivateQueueContext 
{ 
    if (!_defaultPrivateQueueContext) { 
     _defaultPrivateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
     _defaultPrivateQueueContext.persistentStoreCoordinator = self.persistentStoreCoordinator; 
    } 
    return _defaultPrivateQueueContext; 
} 

- (NSManagedObjectContext *)mainThreadContext { 
    if (!_mainThreadContext) { 
     _mainThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
     _mainThreadContext.parentContext = [self defaultPrivateQueueContext]; 
    } 
    return _mainThreadContext; 
} 

+ (NSManagedObjectContext *)newPrivateQueueContext 
{ 
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
    context.parentContext = [[self sharedParliamentAPI] mainThreadContext]; 

    return context; 
} 

스레드에서 교착 상태가 발생 (A는 요청을 가져 실행하려고 할 때) :

- (void)fetchMenuItemsWithCompletion:(void (^) (BOOL success, NSString *message))completionBlock { 
    NSMutableURLRequest *request = [APIHelper createNewRequestWithURLExtension:@"menuitems" httpMethodType:@"GET" parameters:nil]; 
    NSURLSession *session = [NSURLSession sessionWithConfiguration:self.sessionConfig]; 
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 

     NSObject *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 
     if ([[json valueForKey:@"isSuccess"] boolValue]) { 

      NSManagedObjectContext *defaultContext = self.defaultPrivateQueueContext; 
      NSManagedObjectContext *privateQueueContext = [ParliamentAPI newPrivateQueueContext]; 

      [privateQueueContext performBlock:^{ 
       __block NSError *error; 
       NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"MenuItem"]; 
       NSArray *fetchedRecords = [privateQueueContext executeFetchRequest:request error:&error]; 

       // do stuff with fetchedRecords 

      }]; 
     } else { 
      completionBlock([[json valueForKey:@"isSuccess"] boolValue], [json valueForKey:@"message"]); 
     } 
    }]; 
    [dataTask resume]; 
} 
+0

'mainThreadContext'는 무엇을 사용합니까? performBlock 또는 performBlockAndWait를 통해 해당 컨텍스트를 사용하는 * everything *이 있습니까? 그렇지 않으면 아이에게 교착 상태가 발생할 수 있습니다. – quellish

+0

이 코드가 실행될 때 mainThreadContext가 사용되지 않습니다. 예, 컨텍스트를 사용하는 모든 것이 performBLock을 통해 수행됩니다 – Lneuner

+0

루트 컨텍스트를 새 하위 컨텍스트의 부모로 설정하고 주 스레드 컨텍스트를 제거하더라도 여전히 교착 상태입니까? – quellish

답변

2

귀하의 코어 데이터 객체의 구조는 다음과 같습니다

enter image description here

루트로 NSPrivateQueueConcurrencyType 컨텍스트가 어디 컨텍스트는 자식 저장 노드 NSMainQueueConcurrencyType을 가지며, 차례로 NSPrivateQueueConcurrencyType 컨텍스트를 갖습니다. 이 구조는 IntarWebs에 쓰는 많은 사람들이 권장합니다.

기본 대기열 컨텍스트 인 개인 대기열 컨텍스트가 사용 중이므로 대기 상태가됩니다. 주 대기열 컨텍스트는 모든 작업에 주 대기열을 사용하기 때문에이 경우 대기열 데이터 작업을 수행하는 것이 반드시 바쁜 것은 아닙니다 (그래도 여전히 다소 그렇지만). 메인 큐는 Core Data 이외의 많은 작업을 수행하며, 메인 큐 컨텍스트와 통신해야 할 때마다 이러한 모든 것들이 자식에게 영향을 미치게됩니다.

또한 NSMainQueueConcurrencyType으로 만든 컨텍스트는 명시 적으로 performBlock: 또는 performBlockAndWait:을 사용하지 않고 코어 데이터 작업을 실행할 수 있습니다.

NSArray *results = nil; 
NSError *error  = nil; 
results = [mainQueueContext executeFetchRequest:fetchRequest error:&error]; 

하고 있지 는 이렇게 필요하다 : 예를 들어, 메인 큐 문맥이 할 수

[mainQueueContext performBlock:^{ 
    NSArray *results = nil; 
    NSError *error  = nil; 
    results = [mainQueueContext executeFetchRequest:fetchRequest error:&error]; 
}]; 

여기서 차이는 performBlock:없이 첫 번째 예는 차단한다는 것이다 메인 thread는 결과를 기다리고있다. 두 번째는 performBlock:을 사용하여 비동기식이며 차단하지 않습니다. 가져 오기 요청은 대기열에서 실행되도록 예약됩니다. 분명히, 첫 번째 예제는 어떤 하위 컨텍스트에서 어떤 경합을 일으킬 수 있습니다.

구성에 NSMainQueueConcurrencyType 컨텍스트의 하위 항목 인 NSMainQueueConcurrencyType 컨텍스트가있는 경우 이는 ... 나쁜 것입니다. 거의 그 구성에서 교착 상태가 보장됩니다. 좋은 소식은 문제가 없습니다.

NSMainQueueConcurrencyType 컨텍스트를 사용하여 코드를 performBlock:으로 변환하면이 부분을 완화 할 수 있습니다. 메인 큐 컨텍스트 대신에 NSPrivateQueueConcurrencyType을 사용할 수도 있습니다. 메인 큐 컨텍스트를 전혀 사용하지 않는 이유는별로 없습니다. NSFetchedResultsController can be used with a private queue context to do "background fetching".

+0

심층적 인 답변 주셔서 감사합니다. 나는 그것을 시도 할 것이다. – Lneuner

관련 문제