Swift 2 : Try/Catch a non-throwing function - swift

I'm refactoring a Obj-c class where there was a #try/#catch block around removeObserver:.
Doing the same thing in swift triggers a warning since removeObserver might fail (when there is no observer) but it doesn't throw any errors.
Any idea how I could achieve the same behaviour ?
edit : My code :
try {
self.removeObserver(self, forKeyPath: "LineDisplayChanged")
}

The func removeObserver(_ anObserver: NSObject,forKeyPath keyPath: String) you are calling is from the NSKeyValueObserving protocol and does not throws any exceptions.
Also, note that in Swift 2 the syntax for exception(that are actually ErrorType enum subclasses) has changed and is now something like this:
do{
try functionThrowingExceptions()
}catch ErrorTypeSubclassEnum.Value {
// Do something
}catch ErrorType {
// Do something, catches everything else
}
See this post for more info.
Note: I'm using KVO with the latest beta of XCode7, doing a self.removeObserver(self, forKeyPath: "path") does not trigger any error/warning.

To remove warning just remove try { }. removeObserver:forKeyPath: is throwing an exception and not an error. And you cannot catch exceptions in Swift so make sure you call this method only if you observing it otherwise it will crash and there is no way around it in Swift.
You could write a category in Objective-C that wraps this call and capture the exception and returns an error instead.

Related

Exception handling with Swift 2 to 4 Migration

I'm migrating some code originally written in Swift2 to Swift4. I've completed the Swift3 intermediate upgrade and am hitting some errors in Xcode9 regarding some user defined enum uses outside their source file.
Consider the following partial project structure...
Project
--EnumDefs
----ExceptionTypes.swift
--UI
----UseExceptions.swift
ExceptionTypes.swift
enum MyError : Error {
case err1
case err2
}
...
UseExceptions.swift
...
do {
...
} catch MyError.err1(let e) {
print("\(e)")
} catch let e {
print("\(e)")
}
...
I've also tried the variant syntax I've seen online of
catch let e as MyError.err1 {
still no luck, I'm seeing the compiler error:
Enum element 'err1' is not a member type of 'MyError'
I'm tried making the MyError scope to be defined public which didn't work. I get a sense that I may be missing an import or something. I'm not sure if it matters but Autocomplete in Xcode from the UseExceptions.swift file does recognize when I begin typing MyError.
Is there anything special to using definitions between swift files across a sibling directory like shown above? Or is there something else wrong here with the way Swift 4 deals with exception handling?
You are missing an associatedValue, case err1(String)
func test() throws {
throw MyError.err1("error")
}
enum MyError : Error {
case err1(String)
case err2
}
do {
try test()
} catch MyError.err1(let e) {
print(e)
}
Looks like #zombie was right, it was a matter of old style Exception handling. I removed the substantive use of the print("\(e)") from the err1 handler and the compiler error went away.
I'm curious what the exception handling capabilities were like in Swift 2 that allowed the earlier syntax and exception object usage.

Does throwing a asynchronous function make it synchronous in Swift?

This is a code example taken from Perfect Swift PostgresSTORM library.
do{
//Create a user object
let obj = User()
obj.name = "someUser"
//Save it to db
try obj.save({ id in
print(2..)
obj.id = id as! Int
})
print("1..")
}catch{
print("Something went wrong.")
}
//Go to next page
print("3..")
I expected to see the print logs to be
1..
3..
2..
but, The logs looked like this.
2..
1..
3..
It's highly unlikely for "2.." to print before "1..". Is it the "try" that's making it to run as a synchronous function?
It's totally up to PostgresSTORM implementation of save. I'm not familiar with it so I can't say whether it's actually asynchronous or not but I can offer you two dummy implementations, one asynchronous and one synchronous of a method with a similar signature.
Asynchronous:
func save(callback: #escaping (Int) -> Void) throws {
OperationQueue.main.addOperation {
callback(0)
}
}
Synchronous:
func save(callback: (Int) -> Void) throws {
callback(0)
}
(Note that it doesn't throw any exception in this example just for simplicity's sake).
try is required by Swift compiler when you call a function that might throw an exception and has no impact in (a)synchronous execution of the method. In fact try is just required to ensure that when we use the method we are well aware about it possibly throwing an exception.
I might be wrong but if this is SwiftORM's implementation of save method then callback is always synchronously called.

Swift Do Try Catch behaviour

I was dealing with a class where I have implemented a do-try-catch clause.
Basically the problem is that the code after "try" got executed even though the try fails:
Do{
try jsonparshing(mydata)
code....
}catch{
alert("error")
}
Is it correct to locate the code after try?
I don't want that this code get executed if try fails.
Here are the steps I would do to debug that behavior:
(1) Does your 'jsonparshing(mydata)' really throw?
1.a. You could check the type of the 'jsonParsing(_:)' for the throws keyword.
1.b. Or you could try to omit the 'do { } catch {}' and 'try' altogether to see if Xcode complain that the function throws and should use try.
// btw. is that a typo? Maybe 'jsonParsing(myData)' is more custom.
(2) Assuming you past check in (1). I.e. the function really throw. Then you could replace your 'jsonParsing(_:)' with a mock one just to convince yourself that the Swift 'do {} catch {}' does work. There could be something else in your code that might cause the unexpected behavior.
enum SimpleError: Error {
case userError(msg: String)
case systemError(msg: String)
}
func alwaysThrow() throws -> () {
throw SimpleError.userError(msg: "I create error!")
}
do {
print("before throw") // printed
try alwaysThrow()
print("after throw") // not printed
} catch {
print(error) // print: "userError("I create error!")\n"
}
(3) At this point, if it is not a user/programmer mistake, then focus your attention on the 'jsonParsing(_:)' as there is where the culprit is.

Is there a way to throw errors from asynchronous closures in Swift 3?

I’m executing some functions in a test asynchronously using a DispatchQueue like this:
let queue: DispatchQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated)
let group: DispatchGroup = DispatchGroup()
func execute(argument: someArg) throws {
group.enter()
queue.async {
do {
// Do stuff here
group.leave()
} catch {
Log.info(“Something went wrong")
}
}
group.wait()
}
Sometimes the code inside the do block can throw errors, that I have to catch later on. Since I’m developing a test, I want it to fail, if the code inside the do block throws an error.
Is there a way to throw an error, without catching it inside the queue.async call?
You cannot throw an error, but you can return an error:
First, you need to make your calling function asynchronous as well:
func execute(argument: someArg, completion: #escaping (Value?, Error?)->()) {
queue.async {
do {
// compute value here:
...
completion(value, nil)
} catch {
completion(nil, error)
}
}
}
The completion handler takes a parameter which we could say is a "Result" containing either the value or an error. Here, what we have is a tuple (Value?, Error?), where Value is the type which is calculated by the task. But instead, you could leverage a more handy Swift Enum for this, e.g. Result<T> or Try<T> (you might want to the search the web).
Then, you use it as follows:
execute(argument: "Some string") { value, error in
guard error == nil else {
// handle error case
}
guard let value = value else {
fatalError("value is nil") // should never happen!
}
// do something with the value
...
}
Some rules that might help:
If a function calls an asynchronous function internally, it inevitable becomes an asynchronous function as well. *)
An asynchronous function should have a completion handler (otherwise, it's some sort of "fire and forget").
The completion handler must be called, no matter what.
The completion handler must be called asynchronously (with respect the the caller)
The completion handler should be called on a private execution context (aka dispatch queue) unless the function has a parameter specifying where to execute the completion handler. Never use the main thread or main dispatch queue - unless you explicitly state that fact in the docs or you intentionally want to risk dead-locks.
*) You can force it to make it synchronous using semaphores which block the calling thread. But this is inefficient and really rarely needed.
Well, you might conclude, that this looks somewhat cumbersome. Fortunately, there's help - you might look for Future or Promise which can nicely wrap this and make the code more concise and more comprehensible.
Note: In Unit Test, you would use expectations to handle asynchronous calls (see XCTest framework).
Refactor your code to use queue.sync and then throw your error from there. (Since your execute function is actually synchronous, given the group.wait() call at the last line, it shouldn't really matter.)
For instance, use this method from DispatchQueue:
func sync<T>(execute work: () throws -> T) rethrows -> T
By the way, a good idiom for leaving a DispatchGroup is:
defer { group.leave() }
as the first line of your sync/async block, which guarantees you won't accidentally deadlock when an error happens.

Purpose of try! in Swift

I am confused as what exactly is the purpose of try!. The documentation says that you can use try! to call methods that can throw exception but try! is used as a promise from the caller that it will not throw an exception or the developer is not interested in the result of the exception.
So, if the developer is not interested in catching that exception then why even throw the exception from the method in the first case.
func foo() throws {
}
try! foo()
Why not:
func foo() {
}
foo()
struct Error:ErrorType{}
// function is defined somewhere
// i know just the declaration
//
// func foo(i:Int!) throws -> Void
//
func foo(i: Int!) throws {
if i == nil {
throw Error()
}
}
// i am sure the call is 'safe'
// this simplifies my code
try! foo(2)
//foo(2) // error: call can throw but is not marked with 'try'
let str = "2,2" // mimic result of some operation
do {
// i am not sure if str represents an Int
try foo(Int(str))
} catch {
print("error")
}
A function could throw errors if it gets illegal parameters. However, if this function is used with an UI that allows only the input of legal parameters, then you can call this function with try!, because you are sure that the exception is never thrown.
I read a book on Swift that says you can use try! in the early stages of development, because the app will crash if an error is thrown, so a developer or tester cannot overlook this error. However, I wouldn't use this, because it could be forgotten to remove a try! before the code goes into production.