2

I'm trying to update some of the properties of my Core Data model using .setValue(value:, forKeyPath:) method. On my model, I have one entity called "Alumno", which has an attribute called "especialidadRelacionada" related to another entity, called "Especialidad". It's a many-to-one relationship, as an "Alumno" can only has one "Especialidad", although an "Especialidad" can be matched to many "Alumnos". "Especialidad" entity has, as well, "nombre" as its main attribute. Here the two swift files, as generated from Xcode, from deep inside developer folders:

extension Alumno {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Alumno> {
        return NSFetchRequest<Alumno>(entityName: "Alumno")
    }

    @NSManaged public var correo: String?
    @NSManaged public var foto: Data?
    @NSManaged public var movil: String?
    @NSManaged public var nombre: String?
    @NSManaged public var repertorio: String?
    @NSManaged public var cursoRelacionado: Curso?
    @NSManaged public var ensayosRelacionados: NSSet?
    @NSManaged public var especialidadRelacionada: Especialidad?
    @NSManaged public var tutorRelacionado: Tutor?

}


extension Especialidad {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Especialidad> {
        return NSFetchRequest<Especialidad>(entityName: "Especialidad")
    }

    @NSManaged public var nombre: String?
    @NSManaged public var alumno: NSSet?
    @NSManaged public var obra: NSSet?

}

I get the string for "Especialidad" to be set from a text field user writes in:

@IBOutlet weak var especialidadField: UITextField!

But, when I try to UPDATE "Especialidad" data (previously saved to Core Data with no problem at all), with user's written string:

    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    alumno?.setValue(especialidadField.text, forKey: "especialidadRelacionada.nombre")
do {
    try context.save()
    } catch {
    ...
}

I get this error: "Failed to call designated initializer on NSManagedObject class". It seems that something is incorrect with my "forKey" string, but I can't find what, after so much time looking for it on the internet.

Thanks!

arroyot24
  • 39
  • 1
  • 4
  • 1
    The error is unrelated to the code you've posted. See [here](https://stackoverflow.com/a/33307824/3985749) for an explanation of that error. – pbasdf Aug 31 '20 at 21:21
  • But I have defined my "Alumno" and "Especialidad" correctly at the beginning of may class, I think: – arroyot24 Aug 31 '20 at 21:28
  • ... and the rest of non-related properties update without problem. So the initialization of the instance is correct, I think: – arroyot24 Aug 31 '20 at 21:36
  • I think the problem with your `forKey:` is that you should be using `forKeyPath:` in order to traverse the relationship. – pbasdf Sep 01 '20 at 11:03
  • Thanks! I think so as too. But I don’t find the exact syntax to match my needs. Any suggestion? – arroyot24 Sep 01 '20 at 14:12
  • Out of interest, why are you using key-value coding rather than custom accessors: `alumno.especialidadRelacionada.nombre = especialidadField.text`? – pbasdf Sep 01 '20 at 14:19
  • Because if I use custom accesors, it updates not only the string on "Alumno", but as well, due to its connection, on "Especialidad" entity. The aim is update "Alumno" (parent) data with another among "Especialidad" values, but not force updating "Especialidad" (children) value due to its change on "Alumno. And, as far as I know, the only way to do it is with setValue. – arroyot24 Sep 01 '20 at 16:24
  • In fact, the option offered by the user "pbasdf" gives the same result: it changes the ORIGIN text on "Especialidades", not the relation itself, I mean, change the value of "EspecialidadRelacionada" to another "Especialidad": just that. – arroyot24 Sep 01 '20 at 16:34
  • In that case, you need to fetch the `Especialidad` with the required `nombre` (or create it if it doesn't already exist) and then assign that to `especialidadRelacionada` of your `alumno`. – pbasdf Sep 01 '20 at 18:15
  • Yes! That's it! As I suspected, it was something about the syntax. This has worked: `alumno?.setValue(especialidadSeleccionada, forKey: "especialidadRelacionada")` – arroyot24 Sep 01 '20 at 18:49

1 Answers1

-1
var alumno: Alumno?
var esNuevo: Bool = true
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var especialidadSeleccionada: Especialidad?
var cursoSeleccionado: Curso?
var tutorSeleccionado: Tutor?
arroyot24
  • 39
  • 1
  • 4