I'm trying to create a DB Transaction following a safe path. So I'd like to do something using "do catch" statement, I'm wondering something like that:
do {
try? db.endTransaction()
}catch{ //THIS WHOLE CODE CRASHES
print(error.localizedDescription)
db.rollbackTransaction()
}
However, something is going wrong using this syntaxe. What am I doing wrong? Is this the best way to do what I want?
Inside a do block, you should remove the ? on try because the whole point of do is to catch errors that are thrown by things called with try. Once you do that, if your endTransaction() throws an exception, it should be caught by your catch block.
Related
I thought I was doing it correctly.
let realm = try! Realm()
do {
try realm.write {
realm.add(myObject)
}
} catch {
print("something went wrong!")
}
But I'm still getting a crash instead of that print statement. I'm not interested in avoiding the exception (in this case I caused it deliberately by adding an object with an existing primary key) but I want to be able to catch it and prevent a crash no matter what. Is this possible, and if so, how?
Realm Swift throws Objective-C exceptions only for things that are considered to be programmer error. These exceptions are not intended to be caught and handled at runtime as they're indicative of an error in the program that must be fixed.
I've getting intermittent results on deletion. Sometimes the objects will delete, but most the time when I restart the project or even directly after the delete code, the store still pulls up instances of the objects. I'm deleting through a reference to managedObjectContext from the AppDelegate and making sure I save post delete.
if let object = getById(id, context: context){
context.deleteObject(object)
do{
print("Deleteing object by id")
try context.save()
}catch{
print("Unable to delete object for some reason")
}
}
If I run a getById() with the same id again right after I've successfully saved my deletion, it finds the object again. The error block never triggers, so I figure there is something else going wrong here. Any ideas where to look?
I think you are deleting the found object before entering the do loop and the context.save() is saving it back. That is probably the reason the Error block is not triggering when you look for the object.
try -
if let object = getById(id, context: context) {
do {
try context.deleteObject(object)
try context.save() (I am still not sure if this statement should be there!!!)
print()
}catch{
print()
}
}
Hope that helps.
Figured it out. Deleting was always working fine, the problem was that the identifiers to which I was fetching in my getById() method were not always unique. This caused intermittent deleting to occur because if there were 7 objects with id 1, than there was a 1/7 chance the first object was in fact the one I wished to be deleted.
Long story short, examine the whole problem, and don't make assumptions unless your sure in my case here, that the getById() was actually returning the desired object.
Please correct me if I'm wrong, but from what I understand with Swift 2.0 Apple really encourage you against having many catch statements to handle different error types. Instead in most cases your do-catch block would have only one catch statement that catches everything.
I'm not saying that this is a good or bad idea. But I just don't see any other option. You can't be 100% sure about error type that you may or may not receive after a function call. This is because there is no way to specify a list of possible errors in a function definition after "throws" statement. So you would need to dig into the call stack of the function to find this out. And this could be a very deep stack... Will anyone actually do this every time just to get the idea what to catch?
To demonstrate what I mean:
func funcA() throws {
throw SomeError
}
func funcB() throws {
if something {
throw OtherError
}
try funcA()
}
func funcX() throws {
try funcB()
}
Now I if I want to call funcX - I don't really know that it can throw SomeError or OtherError by looking at funcX definition. In order to find this out I will need to go and review the entire call stack tree from funcX. While it doesn't look too complex in the extremely short example above. But in a real world source code this may become an issue.
Let me preface this by saying my code was working yesterday. I rolled back my commits to the time when it was working.
The only thing that is different is that a migration was ran today to remove some columns from some tables. I can't see how this would affect it
I'm doing google oauth authentication and in my callback url from google I am doing a lot of saves/updates/etc.. My controller calls a single service that does everything. If I query the data while at a breakpoint where the return statement is, I can see the data. There are no exceptions, validation errors, or anything that would lead me to believe anything is wrong. Any ideas?
class MyController {
def myService
def callback() {
myService.update()
//At this point when I run X.get(1) it is returning null
redirect uri: "..."
}
}
#Transactional
class MyService {
def update() {
...
//If I break at this return statement I can run X.get(1) and it returns
return someData;
}
}
Edit: I've found the cause, however I don't understand how this is happening. I'm eventually calling userDetailsService.loadUserByUsername. That method is throwing a NoStackUsernameNotFoundException. I'm catching that exception in my code, however it is causing the transaction to roll back regardless.
Any exception thrown during a transaction, even if you catch it and deal with it, will cause the transaction to roll back.
To get around this you have a couple of options:
Perform a check before the point at which the exception is raised, and don't execute the offending code under conditions where you know it would throw an exception
Do the transaction handling yourself -
In your service, set
static transactional = false
Then declare your own transaction block:
MyDomain.withTransaction { tx ->
try {
userDetailsService.loadUserByUsername(...)
} catch (NoStackUsernameNotFoundException e) {
log.warn("Can't load user...")
}
//stuff you try to persist here will
//be written to the database successfully
//despite the NoStackUsernameNotFoundException
//being thrown & caught
}
In Swift, NSKeyedUnarchiver.unarchiveObjectWithData(data) will throw an exception if data can't be unarchived.
There are some situations where we have no guarantee if that the data is not corrupted, such as when reading from a file.
I am not aware of a try/catch mechanism in Swift, nor that I know of a method like canUnarchive that would help prevent the exception.
Besides implementing the try/catch in Obj-C, is there a pure Swift solution to this problem?
Because unarchiveObjectWithData() doesn't throw its exception, there is currently no way to catch it in Swift (as of writing). The iOS 9 SDK has added a new NSKeyedUnarchiver method decodeTopLevelObject() which now throws an error. You can catch this with the do, try, catch control flow.
do {
let result = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSData(...))
} catch {
print(error)
}