Я сталкивался с этим раньше, и это сложная проблема.
Я решил ее, выполнив загрузку в отдельных фоновых потоках (так же, как вы делаете сейчас), но все операции записи данных кода происходят вглобальная очередь NSOperation с numConcurrentOperations, установленной в 1. Когда каждая фоновая загрузка была завершена, она создала NSOperation и поместила его в эту очередь.
Хорошо: Очень простая безопасность потока - NSOperationQueue гарантировал, что только один поток записывал вCoreData в любой точке.
Плохо: незначительный удар по производительности, потому что операции с Core Data работали последовательно, а не параллельно.Этого можно избежать, выполнив любые вычисления, необходимые для данных в фоновом потоке загрузки, и сделав как можно меньше операций с основными данными.