I have just downloaded the new Xcode 7.0 beta and did a migration from Swift 1.2 to Swift 2. The migration apparently did not change the whole code, in fact a method saveCon
The first of the two errors you provided is misleading, but the second is spot on. The problem is in !moc.save()
which as of Swift 2, no longer returns Bool and is instead annotated throws
. This means that you you have to try
this method and catch
any exceptions that it may emit, instead of just checking wether its return value is true or false.
To reflect this, a new project created in Xcode 7 using Core Data will produce the following boilerplate code which can replace the code you're using.
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()
}
}
}
The answer by 0x7fffffff is correct, but to improve upon Apple's boilerplate code, you can catch the specific error in the catch block using catch let error as NSError
like so:
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch let error as NSError {
NSLog("Unresolved error \(error), \(error.userInfo)")
// Handle Error
}
}
}
The best practice is to use the var error
witch will still be available if you just use it this way :
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
NSLog("Unresolved error \(error), \(error.userInfo)")
// Handle Error
}
}
}
In the same way, if you are sure that managedObjectContext.save()
will not throw
an exception
, the code is slimmed down to:
func saveContext () {
if managedObjectContext.hasChanges {
try! managedObjectContext.save()
}
}
And to extrapolate on why managedObjectContext
is not optional in the Swift 2 code, it is because the NSManagedObject(concurrencyType:)
is an initializer that does not fail. In Xcode 6, the boilerplate code returned an optional context if the NSPersistentStoreCoordinator
is nil, but you can handle this easily by checking.
lazy var managedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var moc = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
moc.persistentStoreCoordinator = coordinator
return moc
}()