Как определить отношения CoreData в Swift?
В CoreData я определил неупорядоченное отношение to-many от Node
до Tag
. Я создал объект Swift следующим образом:
import CoreData
class Node : NSManagedObject {
@NSManaged var tags : Array<Tag>
}
Теперь я хочу добавить Tag
в экземпляр Node
, например:
var node = NSEntityDescription.insertNewObjectForEntityForName("Node", inManagedObjectContext: managedObjectContext) as Node
node.tags.append(tag)
Однако это не выполняется со следующей ошибкой:
Завершение приложения из-за неперехваченного исключения "NSInvalidArgumentException", причина: "Недопустимый тип отношения для многих: property =" tags "; желаемый тип = NSSet; данный тип = _TtCSs22ContiguousArrayStorage000000000B3440D4; value = ( msgstr" ).
Каков правильный тип отношений to-many?
Ответы
Ответ 1
Чтобы иметь возможность работать с отношениями "один ко многим" в Swift, вам нужно определить свойство как:
class Node: NSManagedObject {
@NSManaged var tags: NSSet
}
Если вы попытаетесь использовать NSMutableSet
, изменения не будут сохранены в CoreData. И, конечно, рекомендуется определить обратную ссылку в Node
:
class Tag: NSManagedObject {
@NSManaged var node: Node
}
Но все же Swift не может генерировать динамические аксессоры во время выполнения, поэтому нам нужно определить их вручную. Очень удобно определять их в классе extension
и помещать в файл Entity+CoreData.swift
. Bellow - это содержимое файла Node+CoreData.swift
:
extension Node {
func addTagObject(value:Tag) {
var items = self.mutableSetValueForKey("tags");
items.addObject(value)
}
func removeTagObject(value:Tag) {
var items = self.mutableSetValueForKey("tags");
items.removeObject(value)
}
}
Использование:
// somewhere before created/fetched node and tag entities
node.addTagObject(tag)
Важно: Чтобы все это работало, вы должны убедиться, что имена классов объектов в вашей модели CoreData содержат имя вашего модуля. Например. MyProjectName.Node
Ответ 2
Как и в Xcode 7 и Swift 2.0, примечание к выпуску 17583057 гласит:
Атрибут NSManaged может использоваться как с методами, так и с свойства, для автоматического доступа к базовым Datas Ключ-кодирование, совместимый со многими аксессуарами.
@NSManaged var employees: NSSet
@NSManaged func addEmployeesObject(employee: Employee)
@NSManaged func removeEmployeesObject(employee: Employee)
@NSManaged func addEmployees(employees: NSSet)
@NSManaged func removeEmployees(employees: NSSet)
Они могут быть объявлены в вашем подклассе NSManagedObject. (17583057)
Итак, вам просто нужно объявить следующие методы, и CoreData позаботится об остальном:
@NSManaged func addTagsObject(tag: Tag)
@NSManaged func removeTagsObject(tag: Tag)
@NSManaged func addTags(tags: NSSet)
@NSManaged func removeTags(tags: NSSet)
Ответ 3
На самом деле вы можете просто определить:
@NSManaged var employees: Set<Employee>
И используйте методы insert
и remove
Set
напрямую.
Ответ 4
Основываясь на ответе @Keenle, если вы хотите быть нахальным и лаконичным и быть в состоянии сказать
node.tags.append(tag)
можно обернуть вызов self.mutableSetValueForKey:
class Node: NSManagedObject {
var tags: NSMutableOrderedSet {
return self.mutableOrderedSetValueForKey("tags")
}
}