Как определить отношение CoreData в Swift?
В CoreData я определил неупорядоченное отношение ко многим из 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; значение = ("<_TtC8MotorNav3Tag: 0xb3437b0> (сущность: тег; id: 0xb343800; данные: {...})").'
Каков правильный тип для отношений ко многим?
4 ответа
Чтобы иметь возможность работать с отношением один-ко-многим в Swift, вам нужно определить свойство как:
class Node: NSManagedObject {
@NSManaged var tags: NSSet
}
Если вы попытаетесь использовать NSMutableSet
изменения не будут сохранены в CoreData. И, конечно, рекомендуется определить обратную ссылку в Node
:
class Tag: NSManagedObject {
@NSManaged var node: Node
}
Но все же Swift не может генерировать динамические средства доступа во время выполнения, поэтому нам нужно определить их вручную. Их очень удобно определять в классе extension
и положить в Entity+CoreData.swift
файл. Сильфонное содержание 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
Начиная с Xcode 7 и Swift 2.0, в примечании к выпуску 17583057 говорится:
Атрибут NSManaged может использоваться как с методами, так и со свойствами, для доступа к автоматически генерируемым методам Key Data-Key-Value-Coding-совместимым для многих методов доступа.
@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)
Так что вам просто нужно объявить следующие методы, а Core Data позаботится обо всем остальном:
@NSManaged func addTagsObject(tag: Tag)
@NSManaged func removeTagsObject(tag: Tag)
@NSManaged func addTags(tags: NSSet)
@NSManaged func removeTags(tags: NSSet)
На самом деле вы можете просто определить:
@NSManaged var employees: Set<Employee>
И использовать insert
а также remove
методы Set
непосредственно.
Основываясь на ответе @Keenle, если вы хотите быть нахальным, лаконичным и уметь говорить
node.tags.append(tag)
можно обернуть вызов self.mutableSetValueForKey:
class Node: NSManagedObject {
var tags: NSMutableOrderedSet {
return self.mutableOrderedSetValueForKey("tags")
}
}