Как упоминалось в сессии WWDC 2014 225 (Что нового в основных данных), Основные данные на iOS 8 и OS X Yosemite теперь поддерживают аргумент командной строки -com.apple.CoreData.ConcurrencyDebug 1
для включения утверждений, которые обнаруживают нарушения контракта Core Data concurrency.
В моих экспериментах с этим я обнаружил, что он работает под iOS 8 beta 1 (как на устройстве, так и в симуляторе), но я, кажется, нашел ложный результат, т.е. фреймворк бросает исключение нарушения многопоточности где он не должен этого делать. По крайней мере, я верю.
Вопрос: верен ли код ниже или я делаю что-то, что нарушает модель потоковой обработки Core Data?
Я создаю очень простой стек Core Data (с сохранением в памяти для простоты) с контекстом управляемого объекта с именем backgroundContext
с приватной очередью concurrency. Затем я вызываю performBlockAndWait { }
в этом контексте, а в блоке я создаю новый управляемый объект, вставляю его в контекст и сохраняю.
Операция сохранения - это то, где я получаю исключение нарушения многопоточности из Core Data.
var backgroundContext: NSManagedObjectContext?
func setupCoreDataStackAndViolateThreadingContract()
{
let objectModelURL = NSBundle.mainBundle().URLForResource("CoreDataDebugging", withExtension: "momd")
let objectModel: NSManagedObjectModel? = NSManagedObjectModel(contentsOfURL: objectModelURL)
assert(objectModel)
// Set up a simple in-memory Store (without error handling)
let storeCoordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: objectModel)
assert(storeCoordinator)
let store: NSPersistentStore? = storeCoordinator!.addPersistentStoreWithType(NSInMemoryStoreType, configuration: nil, URL: nil, options: nil, error: nil)
assert(store)
// Set up a managed object context with private queue concurrency
backgroundContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
assert(backgroundContext)
backgroundContext!.persistentStoreCoordinator = storeCoordinator!
// Work on the background context by using performBlock:
// This should work but throws a multithreading violation exception on
// self.backgroundContext!.save(&potentialSaveError)
backgroundContext!.performBlockAndWait {
NSEntityDescription.insertNewObjectForEntityForName("Person", inManagedObjectContext: self.backgroundContext!) as NSManagedObject
person.setValue("John Appleseed", forKey: "name")
var potentialSaveError: NSError?
// In the following line: EXC_BAD_INSTRUCTION in
// `+[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__]:
let didSave = self.backgroundContext!.save(&potentialSaveError)
if (didSave) {
println("Saving successful")
} else {
let saveError = potentialSaveError!
println("Saving failed with error: \(saveError)")
}
}
}
Я тестировал по существу тот же код в Objective-C и получил тот же результат, поэтому я сомневаюсь, что это проблема Swift.
Изменить: если вы хотите запустить код самостоятельно, Я поставил проект на GitHub (требуется Xcode 6/iOS 8 beta).