질문 : 내 NSFetchedResultsController가 UI를 업데이트하도록 트리거하도록 부모 컨텍스트에서 변경 사항이 유지되도록 자식 컨텍스트를 얻으려면 어떻게해야합니까?
설정은 다음과 같습니다.
많은 XML 데이터를 다운로드하고 추가하는 앱이 있습니다 (약 2 백만 개의 레코드, 각각 일반 텍스트 단락 크기). sqlite 파일의 크기는 약 500MB가됩니다. 이 콘텐츠를 Core Data에 추가하는 데는 시간이 걸리지 만 데이터가 데이터 저장소에 점진적으로로드되는 동안 사용자가 앱을 사용할 수 있기를 원합니다. 많은 양의 데이터가 이동되고 있다는 사실은 사용자가 눈에 띄지 않고 인식 할 수 없어야합니다. 따라서 중단이나 지터가 없습니다. 버터처럼 스크롤합니다. 그래도 앱이 더 유용하고 더 많은 데이터가 추가되므로 데이터가 Core Data 저장소에 추가되기를 영원히 기다릴 수 없습니다. 코드에서 이것은 가져 오기 코드에서 다음과 같은 코드를 피하고 싶다는 것을 의미합니다.
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.25]];
이 앱은 iOS 5 전용이므로 지원해야하는 가장 느린 기기는 iPhone 3GS입니다.
현재 솔루션을 개발하기 위해 지금까지 사용한 리소스는 다음과 같습니다.
Apple의 핵심 데이터 프로그래밍 가이드 : 효율적인 데이터 가져 오기
- Autorelease 풀을 사용하여 메모리 유지
- 관계 비용. 플랫 가져 오기, 마지막에 관계 패치
- 도움이된다면 쿼리하지 마세요. O (n ^ 2) 방식으로 속도가 느려집니다.
- 일괄 가져 오기 : 저장, 재설정, 비우기 및 반복
- 가져올 때 실행 취소 관리자 끄기
- 3 가지 컨텍스트 사용 : 마스터, 메인 및 제한 컨텍스트 유형
iDeveloper TV-Mac, iPhone 및 iPad 용 핵심 데이터 업데이트
- performBlock으로 다른 큐에 저장을 실행하면 작업이 빨라집니다.
- 암호화는 속도를 늦추므로 가능하면 끄십시오.
Marcus Zarra의 핵심 데이터에서 대용량 데이터 세트 가져 오기 및 표시
- 현재 실행 루프에 시간을 제공하여 가져 오기 속도를 늦출 수 있으므로 사용자에게 원활하게 느껴집니다.
- 샘플 코드는 대규모 가져 오기를 수행하고 UI 응답 성을 유지할 수 있지만 3 개의 컨텍스트 및 디스크에 비동기 저장을 사용하는 것만 큼 빠르지는 않음을 증명합니다.
내 현재 솔루션
NSManagedObjectContext의 3 개의 인스턴스가 있습니다.
masterManagedObjectContext- 이것은 NSPersistentStoreCoordinator가 있고 디스크에 저장을 담당하는 컨텍스트입니다. 이렇게하면 저장이 비동기식이되어 매우 빠릅니다. 다음과 같이 시작할 때 생성합니다.
masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
mainManagedObjectContext -UI가 모든 곳에서 사용하는 컨텍스트입니다. masterManagedObjectContext의 자식입니다. 다음과 같이 만듭니다.
mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[mainManagedObjectContext setUndoManager:nil];
[mainManagedObjectContext setParentContext:masterManagedObjectContext];
backgroundContext- 이 컨텍스트는 XML 데이터를 Core Data로 가져 오는 역할을하는 NSOperation 하위 클래스에서 생성됩니다. 작업의 주요 방법에서 생성하고 마스터 컨텍스트에 연결합니다.
backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[backgroundContext setUndoManager:nil];
[backgroundContext setParentContext:masterManagedObjectContext];
이것은 실제로 매우 매우 빠르게 작동합니다. 이 3 가지 컨텍스트 설정을 통해 가져 오기 속도를 10 배 이상 향상시킬 수있었습니다! 솔직히 이것은 믿기 어렵다. (이 기본 디자인은 표준 핵심 데이터 템플릿의 일부 여야합니다 ...)
가져 오기 과정에서 두 가지 방법을 저장합니다. 배경 컨텍스트에 저장하는 모든 항목 1000 개 :
BOOL saveSuccess = [backgroundContext save:&error];
그런 다음 가져 오기 프로세스가 끝날 때 마스터 / 부모 컨텍스트를 저장합니다.이 컨텍스트는 표면적으로 기본 컨텍스트를 포함하여 다른 자식 컨텍스트로 수정 사항을 푸시합니다.
[masterManagedObjectContext performBlock:^{
NSError *parentContextError = nil;
BOOL parentContextSaveSuccess = [masterManagedObjectContext save:&parentContextError];
}];
문제 : 문제는 뷰를 다시로드 할 때까지 UI가 업데이트되지 않는다는 것입니다.
NSFetchedResultsController를 사용하여 데이터를 공급받는 UITableView가있는 간단한 UIViewController가 있습니다. 가져 오기 프로세스가 완료되면 NSFetchedResultsController가 부모 / 마스터 컨텍스트에서 변경 사항이 없음을 확인하므로 UI가 익숙한 것처럼 자동으로 업데이트되지 않습니다. UIViewController를 스택에서 꺼내고 다시로드하면 모든 데이터가 거기에 있습니다.
질문 : 내 NSFetchedResultsController가 UI를 업데이트하도록 트리거하도록 부모 컨텍스트에서 변경 사항이 유지되도록 자식 컨텍스트를 얻으려면 어떻게해야합니까?
나는 앱을 중단시키는 다음을 시도했습니다.
- (void)saveMasterContext {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:@selector(contextChanged:) name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];
NSError *error = nil;
BOOL saveSuccess = [masterManagedObjectContext save:&error];
[notificationCenter removeObserver:self name:NSManagedObjectContextDidSaveNotification object:masterManagedObjectContext];
}
- (void)contextChanged:(NSNotification*)notification
{
if ([notification object] == mainManagedObjectContext) return;
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(contextChanged:) withObject:notification waitUntilDone:YES];
return;
}
[mainManagedObjectContext mergeChangesFromContextDidSaveNotification:notification];
}