ios - persistencia - Swift+CoreData: no se puede establecer un Bool en la subclase NSManagedObject-¿Error?
persistencia de datos en swift 4 (6)
Tengo un pequeño problema extraño que parece que no puedo resolver, tengo una entidad simple con una subclase NSManagedObject personalizada:
@objc(EntityTest) class EntityTest: NSManagedObject {
@NSManaged var crDate: NSDate
@NSManaged var name: String
@NSManaged var completed: Bool
@NSManaged var completedOn: NSDate
}
Este es el problema, puedo crear la multa del objeto y establecer todos los valores y almacenarlos en una matriz. Sin embargo, más tarde, cuando intento recuperar el mismo objeto, puedo establecer todos los valores EXCEPTO el campo "completado". Recibo un error en tiempo de ejecución que dice "EXC_BAD_ACCESS", puedo leer el valor, pero no puedo establecerlo.
El depurador apunta a:
0x32d40ae: je 0x32d4110 ; objc_msgSend + 108
0x32d40b0: movl (%eax), %edx
Tal vez algunos problemas debido a que se trata como una clase de Objective-C y al intentar enviar un mensaje para establecer un valor booleano que sé que es un poco divertido con CoreData originalmente representándolos como NSNumbers.
¿Algunas ideas? Yo mismo creé la clase, no se genera.
EDITAR:
entity.crDate = NSDate() // succeeds
entity.completed = false // fails
entity.completed.setValue(false, forKey: "completed") //succeeds
Así que para configurar el bool, usar setValue de NSManagedObject funciona pero no los setters directos, aunque para las propiedades que no son bools, puedo configurarlo usando los setters.
ACTUALIZAR:
Mientras verifico esto un poco más, parece que la primera vez que establezco el valor después de obtener de NSEntityDescription, utiliza los métodos de acceso Swift normales. Más adelante, cuando trato de acceder al mismo objeto (que estaba almacenado en una matriz), trata de tratarlo como un objeto de estilo Objective-C y envía un mensaje para el método llamado "setCompleted". Supongo que tiene sentido ya que uso la notación de puntos para acceder a ella y usé la directiva @objc.
Probé esto creando un método "setCompleted", sin embargo, en el método establezco el valor usando "completed = newValue" que realiza una llamada recursiva a "setCompleted" causando que se bloquee ... Extraño, por lo que en este momento todavía puedo No tengo una solución adecuada. Parece que solo pasa con Bools.
La única solución es usar el método "setValueForKey" de NSManagedObject. Tal vez archivar esto como un informe de error?
Descubrí que funciona bien si especifica el nombre de la clase y el módulo en el modelo de datos (en lugar de dejar el NSManagedObject
predeterminado).
Una vez que establezca eso, puedo usar Bool
, Int16
, Int32
, etc., sin ningún problema.
En XCode 8 Just set:
user.isLoggedIn = true
funciona como un encanto
No he tocado swift, pero en Objective-C, un BOOL no es un objeto, y no puede ser un objeto. Es una primitiva, y parece que estás tratando de decirle a una clase de Objective-C que trate un BOOL como un objeto. Pero podría estar inventándolo, ya que no estoy familiarizado con lo que @NSManaged hace bajo el capó.
Puede reducir su propiedad de tipo NSNumber a Bool de la siguiente manera:
var someBoolVariable = numberValue as Bool
Funciona para mí de esta manera:
self.twoFactorAuthEnabledSwitch.enabled = userProfile?.twoFactorEnabled as Bool
Si permite que Xcode 6 Beta 3 cree los archivos Swift para sus entidades, creará NSNumber
propiedades CoreData
para Boolean
tipo Boolean
de CoreData
.
Sin embargo, puedes usar Bool como un tipo Swift en lugar de NSNumber, aunque funcionó para mí sin usar la sintaxis de puntos . Establecerá el Swift Bool
con un NSNumber
, que tal vez conduce a un error en la sintaxis de puntos.
Para hacerlo explícito, debe usar el tipo NSNumber
para los atributos en la entidad con el tipo Boolean
. Luego cree una propiedad computada (en iBook El lenguaje de programación Swift en Guía de idiomas -> Propiedades -> Propiedades calculadas) para devolverle un Bool
Swift. Así que nunca realmente almacenaría un Bool
.
Al igual que:
@NSManaged var snack: NSNumber
var isSnack: Bool {
get {
return Bool(snack)
}
set {
snack = NSNumber(bool: newValue)
}
}
Por supuesto, sería bueno ocultar el otro (atributo NSNumber), pero tenga paciencia y Apple implementará atributos privados en el futuro.
Editar:
Si marca la casilla crear tipos de skalar , ¡incluso utilizará el tipo Bool
en el archivo Swift creado automáticamente!
Así que creo que es un error.
Siguiendo de CH Buckingham que es del todo correcto. Está intentando almacenar un tipo primitivo en los datos del núcleo donde está esperando un NSNumber.
El uso correcto sería entity.completed = NSNumber.numberWithBool(false)
Esta es también la razón por la que no puede recuperar este valor completado como un bool directamente y, por lo tanto, tendría que escribir:
var: Bool? = entity.completed.boolValue()