Настройка отношения NSManagedObject в Swift
Как добавить объект к свойству отношений в подкласс NSManagedObject
в Swift?
В Objective-C, когда вы создаете подкласс NSManagedObject
в Xcode из модели данных, есть автоматически созданное расширение класса, которое содержит объявления типа:
@interface MyManagedObject (CoreDataGeneratedAccessors)
- (void)addMySubObject: (MyRelationshipObject *)value;
- (void)addMySubObjects: (NSSet *)values;
@end
Однако Xcode в настоящее время не обладает этой способностью генерации класса для классов Swift.
Если я попытаюсь вызвать эквивалентные методы непосредственно на объект Swift:
myObject.addSubObject(subObject)
... Я получаю ошибку компилятора в вызове метода, потому что эти сгенерированные аксессоры не видны.
Я объявил свойство отношения как @NSManaged
, как описано в документации.
Или мне нужно вернуться к объектам Objective-C для моделей данных с отношениями?
Ответы
Ответ 1
Да, что больше не будет работать, Swift не сможет генерировать аксессоров во время выполнения таким образом, он сломает систему типов.
Что вам нужно сделать, это использовать пути ключей:
var manyRelation = myObject.valueForKeyPath("subObjects") as NSMutableSet
manyRelation.addObject(subObject)
/* (Not tested) */
Ответ 2
Как и Xcode 7 и Swift 2.0 (см. примечание к выпуску # 17583057), вы можете просто добавить следующие определения в сгенерированный файл расширений:
extension PersonModel {
// This is what got generated by core data
@NSManaged var name: String?
@NSManaged var hairColor: NSNumber?
@NSManaged var parents: NSSet?
// This is what I manually added
@NSManaged func addParentsObject(value:ParentModel)
@NSManaged func removeParentsObject(value:ParentModel)
@NSManaged func addParents(value:Set<ParentModel>)
@NSManaged func removeParents(value:Set<ParentModel>)
}
Это работает, потому что
Атрибут NSManaged может использоваться как с методами, так и с свойства, для автоматического доступа к базовым Datas Ключ-кодирование, совместимый со многими аксессуарами.
Добавление этого определения позволит вам добавлять элементы в свои коллекции. Не уверен, почему они не просто сгенерированы автоматически...
Ответ 3
Основные данные в Objective C автоматически создают методы настройки (1):
По умолчанию Core Data динамически создает эффективные общедоступные и примитивные методы get и set accessor для моделируемых свойств (атрибутов и отношений) классов управляемых объектов. Это включает в себя методы кодирования ключа с переменным ключом, такие как addObject: и удаляет:, как описано в документации для объектов mutableSetValueForKey: -managed - эффективно изменяемые прокси-серверы для всех их отношений со многими.
В настоящее время с Swift в Xcode6-Beta2, вам придется реализовать эти аксессуры самостоятельно. Например, если у вас есть отношение неупорядоченных ко многим, от Way
до Node
, вы должны реализовать addNodesObject
следующим образом:
class Way : NSManagedObject {
@NSManaged var nodes : NSSet
func addNodesObject(value: Node) {
self.mutableSetValueForKey("nodes").addObject(value)
}
}
Здесь вы должны использовать mutableSetValueForKey
/mutableOrderedSetValueForKey
/mutableArrayValueForKey
. На этих наборах/массивах вы можете вызвать addObject, и они будут сохранены на следующем флеше.
Ответ 4
Расширение над решением выше одного-многих отношений - это NSMutableSet, поэтому это позволяет вам напрямую добавлять или удалять Person NSManagedObject для Ролей, в этом случае у Человека есть одна Роль, а Роли имеют много Лица (ов)
Я тестировал это решение под Xcode Beta-3, и это работает!
Этот код выводит Департамент, чтобы упростить отображение кода один на один и один на один, необходимый для доступа к ролям от лица и лиц из роли.
import CoreData
@objc(Person) class Person: NSManagedObject {
@NSManaged var name: String
//One to One relationship in your Model
@NSManaged var roles: Roles
}
@objc(Roles) class Roles: NSManagedObject {
@NSManaged var role: String
//One to Many relationship in your Model
@NSManaged var persons: NSMutableSet
}
extension Roles {
func addPersonsObject(value: Person) {
self.persons.addObject(value)
}
func removePersonsObject(value: Person) {
self.persons.removeObject(value)
}
func addPersons(values: [Person]) {
self.persons.addObjectsFromArray(values)
}
func removePersons(values: [Person]) {
for person in values as [Person] {
self.removePersonsObject(person)
}
}
}
Ответ 5
Вместо этого вы можете использовать типизированный Set
, что намного проще. Следуя примеру @Nycen и @lehn0058 в предыдущем ответе, вы можете просто написать:
extension PersonModel {
@NSManaged var parents: Set<ParentModel>?
}
И затем используйте методы insert
и remove
Set
.
Ответ 6
Начиная с Xcode 8 и Swift 3.0, Xcode теперь генерирует аксессоры для отношений. Например, у меня есть класс Store NSManagedObject, который имеет отношение "один-много" к элементам; Я назвал это отношение SellsItems. Сгенерированный класс для Store теперь имеет следующее расширение для добавления и удаления из SellsItems. Добавление или удаление элементов в отношении так же просто, как вызов этих функций.
// MARK: Generated accessors for sellsItems
extension Store {
@objc(addSellsItemsObject:)
@NSManaged public func addToSellsItems(_ value: Item)
@objc(removeSellsItemsObject:)
@NSManaged public func removeFromSellsItems(_ value: Item)
@objc(addSellsItems:)
@NSManaged public func addToSellsItems(_ values: NSSet)
@objc(removeSellsItems:)
@NSManaged public func removeFromSellsItems(_ values: NSSet)
}
Ответ 7
Поскольку вам нужно только установить одну сторону отношения для обоих, которые будут установлены в настоящее время, это особенно просто, если у вас есть отношение 1 ↔ many, например. объект отдела имеет несколько объектов Person, тогда вы можете просто использовать:
aPerson.department = aDepartment
Если вы проверите, вы обнаружите, что aDepartment.people(при условии, что это взаимные отношения, которые вы настроили) теперь будет содержать объект "aPerson" Person.
Если отношение много и меньше многих, то одно из более сложных решений, указанных выше, представляется необходимым.
Ответ 8
Скажем, у вас есть следующие объекты:
В вашей организации Person
у них есть отношение to-many с Role
и to-one с Department
. Ваш управляемый объект может выглядеть примерно так:
class Person : NSManagedObject
{
@NSManaged var roles : Array<Role>
@NSManaged var department : Department
}
Взаимоотношения с инверсиями (все должны иметь их) требуют, чтобы для установления связи была установлена одна сторона.
Например, если вы устанавливаете свойство Person
Department
объекту Department
, свойство обратного Department.people
теперь также имеет этот объект Person
, содержащийся внутри.