Ответ
Нет. Core Data не является потокобезопасной по умолчанию. Объекты NSManagedObjectContext и NSManagedObject должны использоваться только в том потоке (очереди), в котором они были созданы.
Основные правила потокобезопасности:
- Каждый контекст (
NSManagedObjectContext) привязан к конкретной очереди. - Управляемые объекты (
NSManagedObject) нельзя напрямую передавать между контекстами из разных потоков.
Безопасная работа с контекстами:
Используйте методы perform или performAndWait для выполнения операций в правильной очереди.
// Создание приватного контекста для фоновой работы
let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateContext.parent = mainContext
privateContext.perform {
// Все операции с контекстом внутри этого блока
let newItem = Item(context: privateContext)
newItem.name = "Sample"
do {
try privateContext.save() // Сохраняем в приватный контекст
// Для сохранения в persistent store координатору может потребоваться
// сохранение родительского (main) контекста.
} catch {
print("Save error: (error)")
}
// Обновление UI должно происходить на главном потоке
DispatchQueue.main.async {
// Обновить интерфейс
}
}
Рекомендуемые практики для многопоточности:
- Используйте соответствующий тип контекста:
.mainQueueConcurrencyTypeдля UI,.privateQueueConcurrencyTypeдля фоновых задач. - Для передачи изменений между контекстами используйте родительско-дочерние иерархии или слияние через уведомления (
NSManagedObjectContextDidSave). - Для передачи идентификаторов объектов между очередями используйте
NSManagedObjectID.
Ответ 18+ 🔞
А, ну это, классика, блядь! Core Data и потоки — история старая, как мир, и хуёвая, как вчерашний борщ. Слушай сюда, распиздяй.
Нет, сука, неееет! Core Data — она не потокобезопасная, вот нихуя! Это не та штука, которую можно как попало по потокам швырять. Объекты эти, NSManagedObjectContext и NSManagedObject, они как привязанные к своей очереди, блядь. Создали в одном потоке — там и юзайте, пока не надоест. Передавать их в другой поток — это прямой билет в краш, в пизду, в лучших традициях.
Главные правила, которые надо вбить себе в башку:
- Каждый контекст (
NSManagedObjectContext) — это как своя вотчина, своя очередь. Не лезь со своим уставом в чужой монастырь. - Управляемые объекты (
NSManagedObject) — это вообще штука одноразовая в плане потоков. Нельзя просто так взять и перекинуть из одного контекста в другой, если они из разных потоков. Хуй с горы получишь, а не результат.
Как не обосраться с контекстами:
Юзай методы perform или performAndWait. Это как волшебные слова, которые говорят: «Эй, контекст, делай всё в своей родной очереди, а не где попало».
// Создаём приватный контекст для всякой фоновой хуйни
let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateContext.parent = mainContext // Главный контекст — папаша
privateContext.perform { // Всё, вошли в его вотчину
// Теперь тут можно делать что угодно с этим контекстом
let newItem = Item(context: privateContext)
newItem.name = "Sample"
do {
try privateContext.save() // Сохранили в приватный контекст
// Чтобы добралось до постоянного хранилища, может, ещё и главный контекст сохранить придётся.
} catch {
print("Save error: (error)") // Ну вот, опять обосрались
}
// А вот обновлять интерфейс — это уже на главный поток, ёпта!
DispatchQueue.main.async {
// Обновляем UI
}
}
Чтобы жизнь мёдом не казалась, запомни ещё:
- Тип контекста выбирай с умом:
.mainQueueConcurrencyType— для всего, что связано с интерфейсом, а.privateQueueConcurrencyType— для всех этих фоновых вычислительных пизделок. - Чтобы изменения между контекстами передавать, либо делай их родителями-детьми, либо лови уведомления (
NSManagedObjectContextDidSave) и мерьджь, как последний урод. - Если очень надо передать ссылку на объект в другую очередь — тащи не сам объект, а его
NSManagedObjectID. Это как паспорт объекта, по нему в любом контексте можно найти его копию. А сам объект таскать — это, блядь, верный способ всё сломать.
Вот и вся магия, ёпта. Не усложняй, делай по правилам, и будет тебе счастье. А нет — ну, сам знаешь куда.