programming - Swift 2 migration saveContext() en la aplicaciónDelegate
swift lenguaje (2)
Acabo de descargar la nueva versión beta de Xcode 7.0 e hice una migración de Swift 1.2 a Swift 2. Aparentemente, la migración no cambió todo el código, de hecho un método saveContext () que estuvo bien hasta que arrojó 2 errores para la línea:
if moc.hasChanges && !moc.save() {
El operador binario ''&&'' no se puede aplicar a dos operandos Bool
y
La llamada puede lanzar, pero no está marcada con ''probar'' y el error no se maneja
El método se ve así:
// MARK: - Core Data Saving support
func saveContext () {
if let moc = self.managedObjectContext {
var error: NSError? = nil
if moc.hasChanges && !moc.save() {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog("Unresolved error /(error), /(error!.userInfo)")
abort()
}
}
}
¿Alguna idea sobre cómo hacerlo funcionar?
El primero de los dos errores que proporcionó es engañoso, pero el segundo es acertado. El problema está en !moc.save()
que a partir de Swift 2, ya no devuelve Bool y en su lugar es throws
anotados. Esto significa que debe try
este método y catch
las excepciones que pueda emitir, en lugar de simplemente verificar si su valor de retorno es verdadero o falso.
Para reflejar esto, un nuevo proyecto creado en Xcode 7 utilizando Core Data producirá el siguiente código repetitivo que puede reemplazar el código que está usando.
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
NSLog("Unresolved error /(nserror), /(nserror.userInfo)")
abort()
}
}
}
La respuesta por 0x7fffffff es correcta, pero para mejorar el código repetitivo de Apple, puedes detectar el error específico en el bloque catch let error as NSError
usando el catch let error as NSError
así:
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch let error as NSError {
NSLog("Unresolved error /(error), /(error.userInfo)")
// Handle Error
}
}
}
La mejor práctica es utilizar el error
var que seguirá estando disponible si solo lo usa de esta manera:
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
NSLog("Unresolved error /(error), /(error.userInfo)")
// Handle Error
}
}
}
De la misma manera, si está seguro de que managedObjectContext.save()
no generará una exception
, el código se reducirá a:
func saveContext () {
if managedObjectContext.hasChanges {
try! managedObjectContext.save()
}
}
Y para extrapolar sobre por qué managedObjectContext
no es opcional en el código de Swift 2, es porque NSManagedObject(concurrencyType:)
es un inicializador que no falla. En Xcode 6, el código repetitivo devolvió un contexto opcional si NSPersistentStoreCoordinator
es nulo, pero puede controlarlo fácilmente marcando.
lazy var managedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var moc = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
moc.persistentStoreCoordinator = coordinator
return moc
}()