우리는 코어 데이터를 사용하여 수만 개의 객체를 저장하는 엔터프라이즈 수준의 응용 프로그램을 개발하고 있으며 여러 가지 문제가 있습니다.코어 데이터 관리 객체 컨텍스트 디자인 권장 사항
우리의 응용 프로그램에는 필요할 때 데이터를 조작하는 몇 가지 독립적 인 시스템이 있습니다. 이러한 시스템에는 항목 검색, 항목로드, 동기화 및 UI 표시가 포함됩니다. 우리가 소프트웨어를 올바르게 설계한다면, 같은 시스템을 수정하는 다른 시스템으로 인해 아무도 충돌을 병합하지 않아야합니다. 각 시스템에는 고유의 작업 대기열이 있으며 모두 백그라운드에서 수행됩니다. 특히 초기 램프 업 (initial ramp up) 중에 UI 성능 문제를 최소화하기 위해 백그라운드에서 모든 객체 생성 및 수정을 유지하고자합니다. 수천 개의 객체가 서버의 데이터에서 생성 될 수 있습니다. 여기 우리는 다양한 디자인 시도에 몇 가지 문제점을 안고 있습니다. 이러한 ramp가 진행되는 동안 거대한 메모리 소비와 모든 컨텍스트와 자식 컨텍스트의 잘못된 조정으로 인해 교착 상태와 충돌이 발생합니다. 우리는 다음과 같은 디자인을 시도했다 :
- 하나의 루트를 한 아이
NSMainQueueConcurrencyType
컨텍스트를 가지고NSPrivateQueueConcurrencyType
관리되는 개체 컨텍스트를. UI 가져온 결과 컨트롤러는이 하위 컨텍스트를 사용하여 결과를 가져옵니다.NSMainQueueConcurrencyType
자식 컨텍스트에서 우리는 "savingContext"라고하는 하나의NSPrivateQueueConcurrencyType
자식 컨텍스트를 만들고 각각의 백그라운드 작업은 해당 "savingContext"의 자식 컨텍스트를 만들고 변경 한 다음 마지막으로 "깊은 저장"이라고하는 것을 반복적으로 수행했습니다 상단에 저장합니다. 처음에는 많은 다른 하위 컨텍스트의 알림NSManagedObjectContextDidSaveNotification
을 처리 할 필요가 없도록이 디자인을 선택했습니다. 우리는NSPrivateQueueConcurrencyType
컨텍스트에 대한 모든 호출을 포장하고performBlockAndWait:
으로 개체에 액세스했습니다. 기능적으로이 디자인이 수행되었습니다. 모든 변경 사항 및 삽입이 영구 저장소에 저장되었으며 UI가 변경 사항으로 업데이트되었습니다. 이것은 두 가지 이슈를 소개했습니다. 하나는NSMainQueueConcurrencyType
자식 컨텍스트를 통해 병합 된 변경으로 인해 램프 업 중 느린 UI 였고 더 중요한 것은 램프 업 중 매우 높은 메모리 사용량 이었기 때문입니다. 우리는reset
을 컨텍스트 (메인 UI 하위 컨텍스트가 너무 있음)로 호출 할 수 없거나refreshObject:mergeChanges:
을 호출 할 때 지식이 부족하기 때문에 금지 된 RAM 사용법을 쳤습니다. 그래서 우리는 다른 길을갔습니다. - 영구 저장소 조정자와 연결된 두 개의 최상위 컨텍스트, 하위 컨텍스트 저장을위한
NSPrivateQueueConcurrencyType
및 UI 표시를위한NSMainQueueConcurrencyType
이 있습니다.NSMainQueueConcurrencyType
은 기본NSPrivateQueueConcurrencyType
컨텍스트에서NSManagedObjectContextDidSaveNotification
개의 알림을 수신하고 주 스레드에서 병합합니다. 각 백그라운드 작업은 기본NSPrivateQueueConcurrencyType
컨텍스트의 하위 컨텍스트를 만듭니다. 또한 개인 큐 동시성 유형을 사용하여 수행하고, "깊은 저장"을 반복적으로 수행하여 현재 컨텍스트에서 저장을 수행하고, 해당 컨텍스트로 깊은 저장을 재귀 호출합니다. 부모는 현재 컨텍스트에서 다시 설정을 호출하고 다시 저장합니다. 이렇게하면 생성 된 객체가 저장 후에 빠르게 해제되므로 메모리 문제를 피할 수 있습니다. 그러나이 디자인에서는NSMainQueueConcurrencyType
컨텍스트에 대한 알림을 저장하고 있음에도 불구하고 데드 록,NSInternalInconsistencyException
예외 및 가져온 결과 컨트롤러와 같은 많은 문제가 발생했습니다. 또한 UI의 초기로드 시간이 많이 느려집니다. 이전 디자인에서 가져온 결과 컨트롤러는 결과를 매우 빠르게 반환했지만보기가로드 될 때까지 UI가 몇 초 동안 차단되었습니다 (가져온 결과 컨트롤러를viewDidLoad
으로 초기화).
가져온 결과 컨트롤러가 UI 또는 교착 상태와 NSInternalInconsistencyException
예외를 업데이트하지, 중 매우 높은 메모리 사용, 우리는 많은 중간 디자인을 시도했지만 모두 같은 문제를 중심으로 돌고.
나는 정말로 좌절하고 있습니다. 나는 우리의 디자인이 다소 단순해야만하는 것에 대해 명백하게 복잡 해지는 것처럼 느낄 수는 없으며, 우리를 죽이는 기본 사항을 이해하지 못하는 것입니다.
그래서 너희들은 무엇을 제안? 우리의 맥락에서 어떤 배열을 권하고 싶습니까? 다른 스레드에서 서로 다른 컨텍스트를 어떻게 관리해야합니까? 삽입 된 객체를 해제하고 컨텍스트를 재설정하는 모범 사례? 죽은 자물쇠를 피하는가? 이 시점에서 모든 도움을 주시면 감사하겠습니다.
또한 MagicalRecords 카테고리에 대한 권장 사항을 보았습니다. 그것은 권위가 있습니까? 우리는 이미 핵심 데이터 유형을 사용하는데 투자를하고 있으며, MR을 사용하여 마이그레이션하는 것이 얼마나 어려울까요?
비슷한 문제 (아키텍처 하나)가 있습니다. http://stackoverflow.com/questions/15999932/core-data-break-retain-cycle-of-the-parent-context/16008470 - 아키텍처 종류 결국에 갔니? 어떤 팁? – Zyphrax
주 컨텍스트와 상위 루트 컨텍스트가 있습니다. 하지만 루트 컨텍스트는 저장에만 사용되므로 모든 저장시에 다시 설정됩니다. 우리에게는 무수한 이슈가 있습니다. 아이와 부모 컨텍스트의 이러한 새로운 기능은 잘 알려지지 않았으며 많은 버그가 여전히 Apple에 의해 무인으로 남아 있습니다. –
자식 MOC (MainQueue)를 사용하여 루트 MOC (PrivateQueue)로 아키텍처를 배우고'''[self.managedObjectContext refreshObject : self mergeChanges : NO];'''를 호출하여 메모리를 줄입니다. 내 ManagedObjects에서'-didSave'''를 사용합니다. 이렇게하면 관계 사이의 유지주기가 분리되고 모든 MOC가 오브젝트 할당을 해제 할 수 있습니다. NSPrivateQueueConcurrencyType을 가진 MOC 만 개체를 즉시 할당 해제하지 않지만 다음 저장/롤백시 이상한 문제가있는 것 같습니다. – Zyphrax