ios - existing - query core data swift 4
Establecer una relación NSManagedObject en Swift (8)
A partir de Xcode 7 y Swift 2.0 (vea la nota de lanzamiento n. ° 17583057 ), solo puede agregar las siguientes definiciones al archivo de extensión generado:
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>)
}
Esto funciona porque
El atributo NSManaged se puede usar con métodos así como con propiedades, para acceder a los accesos a muchos accesadores de Core Data generados automáticamente y que cumplen con Key-Value-Coding.
Agregar esta definición le permitirá agregar elementos a sus colecciones. No estoy seguro de por qué estos no solo se generan automáticamente ...
¿Cómo se puede agregar un objeto a una propiedad de relación en una subclase NSManagedObject
en Swift?
En Objective-C, cuando genera una subclase NSManagedObject
en Xcode a partir del modelo de datos, hay una extensión de clase generada automáticamente que contiene declaraciones como:
@interface MyManagedObject (CoreDataGeneratedAccessors)
- (void)addMySubObject: (MyRelationshipObject *)value;
- (void)addMySubObjects: (NSSet *)values;
@end
Sin embargo, Xcode carece actualmente de esta capacidad de generación de clases para las clases Swift.
Si intento llamar a métodos equivalentes directamente en el objeto Swift:
myObject.addSubObject(subObject)
... Obtengo un error de compilación en la llamada al método, porque estos accesores generados no son visibles.
He declarado la propiedad de la relación como @NSManaged
, como se describe en la documentación.
¿O tengo que volver a objetos Objective-C para modelos de datos con relaciones?
A partir de Xcode 8 y Swift 3.0, Xcode ahora genera accesos para las relaciones. Por ejemplo, tengo un almacén de clases NSManagedObject, que tiene una relación uno a muchos con Items; He llamado a esa relación SellsItems. La clase generada para Tienda ahora tiene la siguiente extensión para agregar y eliminar de SellsItems. Agregar o eliminar elementos a la relación es tan simple como llamar a estas funciones.
// 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)
}
Como solo necesita establecer un lado de una relación para que ambos se establezcan hoy en día, es particularmente simple si tiene una relación de 1 a - muchos, por ejemplo, un objeto del Departamento tiene múltiples objetos Person, entonces puede simplemente usar:
aPerson.department = aDepartment
Si comprueba que encontrará que unDepartamento.personas (suponiendo que esa sea la relación recíproca que ha configurado) contendrá ahora el objeto Persona ''aPersona''.
Si la relación es muchas <-> muchas, parece necesaria una de las soluciones más complejas anteriores.
En su lugar, puede usar un Set
tipeado que es mucho más fácil. Siguiendo el ejemplo proporcionado por @Nycen y @ lehn0058 en la respuesta anterior, puede simplemente escribir:
extension PersonModel {
@NSManaged var parents: Set<ParentModel>?
}
Y luego usa los métodos de insert
y remove
del Set
.
La ampliación de la solución por encima de una a muchas relaciones es NSMutableSet, por lo que le permite agregar o quitar directamente el Person NSManagedObject a las Roles, en este caso una Persona tiene una Rol y Roles tiene muchas Persona (s)
¡He probado esta solución bajo Xcode Beta-3 y esto funciona!
Este código elimina al Departamento para simplificar la visualización del código de uno a uno y de uno a muchos necesarios para acceder a los roles de una persona y personas de un rol.
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)
}
}
}
Los datos principales en Objective C crean automáticamente métodos setter ( 1 ):
Por defecto, Core Data crea dinámicamente métodos de acceso get y set públicos y primitivos eficientes para propiedades modeladas (atributos y relaciones) de clases de objetos gestionados. Esto incluye los métodos proxy de codificación de valor clave como addObject: y elimina :, como se detalla en la documentación para mutableSetValueForKey: los objetos administrados son proxies efectivamente mutables para todas sus relaciones to-many.
Tal como están las cosas actualmente con Swift en Xcode6-Beta2, tendría que implementar esos accesadores usted mismo. Por ejemplo, si tiene una relación desordenada a muchos, de Way
a Node
, implementaría addNodesObject
esta manera:
class Way : NSManagedObject {
@NSManaged var nodes : NSSet
func addNodesObject(value: Node) {
self.mutableSetValueForKey("nodes").addObject(value)
}
}
La clave aquí es que debe usar mutableSetValueForKey
/ mutableOrderedSetValueForKey
/ mutableArrayValueForKey
. En estos conjuntos / matrices, puede llamar a addObject y se almacenarán en el siguiente color.
Sí, eso ya no va a funcionar, Swift no puede generar accesos en tiempo de ejecución de esta manera, rompería el sistema de tipos.
Lo que tienes que hacer es usar las rutas clave:
var manyRelation = myObject.valueForKeyPath("subObjects") as NSMutableSet
manyRelation.addObject(subObject)
/* (Not tested) */
Supongamos que tiene las siguientes entidades:
- Persona
- Papel
- Departamento
En su entidad Person
, tienen una relación de muchos con Role
y uno con Department
. Su objeto administrado podría verse más o menos así:
class Person : NSManagedObject
{
@NSManaged var roles : Array<Role>
@NSManaged var department : Department
}
Las relaciones con inversos (todos deben tenerlos) solo requieren que se establezca un lado para que se establezca el enlace.
Por ejemplo, si establece la propiedad del department
una Person
en un objeto del Department
, la propiedad Inversa Department.people
ahora también tendrá este objeto Person
contenido dentro.