This question already has answers here:
Swift 2 migration saveContext() in appDelegate
(2 answers)
Closed 7 years ago.
I recently updated Xcode to the new 7.0 beta.
I did the migration with the assistant but there are a few more issues.
func saveContext () {
if let moc = self.managedObjectContext {
var error: NSError? = nil
if moc.hasChanges && !moc.save() {
NSLog("Unresolved error \(error), \(error!.userInfo)")
abort()
}
}
}
On line 4 there are 4 issues:
the first one is:
Binary operator '&&' cannot be applied to two Bool operands
the second one is:
Call can throw, but it is not marked with 'try' and the error is not handled
Can someone please help me?
Here is some code that should do the trick. Remember to preceed throw statements with try and catch them.
func saveContext () {
if let moc = self.managedObjectContext {
if moc.hasChanges {
do {
try moc.save()
} catch {
NSLog("Unresolved error \(error)")
abort()
}
}
}
}
Related
So this is pretty hard to debug. First, that's the basic setup:
I have a method that runs every second:
#objc private func trigger() {
appDelegate.persistentContainer.performBackgroundTask { (privateContext) in
/* modifying database */
do {
// I tried setting a mergePolicy, but it didn't help
privateContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
try privateContext.save()
} catch let error as NSError {
fatalError("Couldn't save private context in Handler: \(error.debugDescription)")
}
}
}
As you see, it's using a private context.
In my appDelegate (where I have the main context) I set this up:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
/* more stuff */
NotificationCenter.default.addObserver(self, selector: #selector(mergeToMainViewContext(notification:)), name: NSNotification.Name.NSManagedObjectContextDidSave, object: nil)
return true
}
func saveContext () {
let context = persistentContainer.viewContext
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy // That's what I added to try. Nothing changed though
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() 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
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
func mergeToMainViewContext(notification: Notification) {
persistentContainer.viewContext.mergeChanges(fromContextDidSave: notification)
}
You see, I added an observer that should fire every time the private context (or any other context) saves.
However, occasionally the app crashes. Most of the time, it crashes without any error messages. Xcode just tells me that it crashes at this line:
persistentContainer.viewContext.mergeChanges(fromContextDidSave: notification)
And that's it :/.
Sometimes though, it crashes and says that there has been a merge conflict. The differences that are listed there are tiny. There are value differences of 0.1 or something. That's why I tried using mergePolicy but it doesn't help.
(I would post this error message, but I don't know how to reproduce this bug)
I have no idea where to look, how to start debugging this. Does anyone have an idea?
Let me know, if you need any more information! Thanks for any help
I'm converting below code to Swift 3.
if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error:nil) {
// 2.
context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics,
localizedReason: "Logging in with Touch ID",
reply: { (success : Bool, error : NSError? ) -> Void in
// 3.
dispatch_async(dispatch_get_main_queue(), {
if success {
self.performSegueWithIdentifier("dismissLogin", sender: self)
}
if error != nil {
var message : NSString
var showAlert : Bool
// 4.
switch(error!.code) {
Step 4 does not work anymore on Xcode 8, Swift 3. So I could not do the following cases:
switch(error!.code) {
case LAError.AuthenticationFailed.rawValue:
message = "There was a problem verifying your identity."
showAlert = true
break;
Currently, it's seems there was no solution that I could find yet. Any suggestion, please let me know.
Thanks a lot!
First change your reply closure of evaluatePolicy method, in Swift 3 it is Error not NSError.
reply: { (success : Bool, error : Error? ) -> Void in
Second, change performSegue with identifier like this.
performSegue(withIdentifier: "dismissLogin", sender: self)
In Swift 3 you need to convert Error object to NSError or use _code with Error instance instead of code.
switch((error! as NSError).code)
OR
switch(error!._code)
You need to also change you dispatch syntax like this.
Dispatch.async.main {
//write code
}
This actually got a lot easier
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Logging in with Touch ID",
reply: { (success : Bool, error : Error? ) -> Void in
// 3.
DispatchQueue.main.async {
if success {
self.performSegueWithIdentifier("dismissLogin", sender: self)
}
if let error = error {
var message : NSString
var showAlert : Bool
// 4.
switch error {
case LAError.userCancel:
//do stuff
This is mostly from memory, but I think it is correct.
This question already has answers here:
How to apply the type to a NSFetchRequest instance?
(10 answers)
Closed 6 years ago.
I opened one of my projects and Xcode asked me for updating source to Swift 3. After clicking save I got as expected an error. The error occurs while creating a fetchRequest. (Error with error message in line 8)
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let appDelegate = UIApplication.shared().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let fetchRequest = NSFetchRequest(entityName:"Sessions") //<- Error error message: generic parameter 'ResultType' could not be inferred
do {
sessions = try managedContext.fetch(fetchRequest) as! [Sessions]
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
print("fetched")
self.tableView.reloadData()
}
}
Also got a solution for this by myself. I just changed from
let fetchRequest = NSFetchRequest(entityName:"Sessions")
to
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName:"Sessions")
I am writing one program on iOS and very race I am facing this error:
2015-11-06 10:57:24.289 NETFNET[2503:976392] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null)
2015-11-06 10:57:24.293 NETFNET[2503:976392] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'
I am trying to access Data Base simultaneously, I think, from main and background threads. I have seen a lot of solutions for Objective C, but none for Swift (I don't know Objective C...). Unfortunately, I don't know how to work with Grand Central Dispatch and, in fact, my program does not really need several treads (I mean it need it, but if some thread loses info from one function for one time, nothing bad will happen). I just want to have stable program on Swift 1 or 2, so I will be thankful for any help.
You need to create a private NSManagedObjectContext with private queue concurrency type and use it to access CoreData whenever operating on a background thread.
So suppose I need to run a database operation on the background, I can dispatch that work to the background thread as
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
//call your background operation.
})
Then in the background operation I can create a private NSManagedObjectContext as
let moc = … //Our primary context on the main queue
let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMOC.parentContext = moc
privateMOC.performBlock {
//operations
do {
try privateMOC.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
Read through Apple's CoreData Concurrency Guide to get a good understanding before implementing core data operations on multiple threads.
Very good. I tried it, it worked fine for me.
Thank you very much.
Previous Code:
do {
try CDHelper.shared.context.save()
}
catch let error as NSError {
// Error mesajlarını ekle!!
print("Could not fetch \(error), \(error.localizedDescription)")
print("Could not fetch \(error), \(error.localizedFailureReason)")
}
// MARK: - CONTEXT
lazy var context: NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType:.MainQueueConcurrencyType)
moc.persistentStoreCoordinator = self.coordinator
return moc
}()
// MARK: - MODEL
lazy var model: NSManagedObjectModel = {
return NSManagedObjectModel(contentsOfURL:self.modelURL)!
}()
// MARK: - COORDINATOR
lazy var coordinator: NSPersistentStoreCoordinator = {
return NSPersistentStoreCoordinator(managedObjectModel:self.model)
}()
lazy var modelURL: NSURL = {
let bundle = NSBundle.mainBundle()
if let url = bundle.URLForResource("Model", withExtension: "momd") {
return url
}
print("CRITICAL - Managed Object Model file not found")
abort()
}()
you should change the code this way:
let moc = NSManagedObjectContext(concurrencyType:.MainQueueConcurrencyType)
let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
privateMOC.parentContext = moc
privateMOC.performBlock({
do {
try privateMOC.save()
} catch {
fatalError("Failure to save context: \(error)")
}
})
Just calling your CoreData Function inside
DispatchQueue.main.async {
...
}
worked for me
You can create an extension for this and wrap the save() function to something like this so you'll just need to use this function instead of save():
extension NSManagedObjectContext {
func update() throws {
let context = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
context.parent = self
context.perform({
do {
try context.save()
} catch {
print(error)
}
})
}
}
How can I print out Core Data save error in Swift?
As far as I have this two lines:
var error: AutoreleasingUnsafePointer<NSError?> = nil
let success = managedObjectContext.save(error)
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch let nserror as NSError {
// 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.
print("Unresolved error \(nserror), \(nserror.userInfo)")
abort()
}
}
}
You have to pass a pointer to an optional NSError object.
As an example, this is the template code from Xcode if you create an iOS app and select
the "Use Core Data" checkbox:
func saveContext () {
if let moc = self.managedObjectContext {
var error: NSError? = nil
if moc.hasChanges && !moc.save(&error) {
// Replace this implementation with code to handle the error appropriately.
// ...
NSLog("Unresolved error \(error), \(error!.userInfo)")
abort()
}
}
}