How to Pass an Error Up the Stack Trace in Swift

How to pass an Error up the stack trace in Swift

Referring to Swift - Error Handling Documentation, you should:

1- Create your custom error type, by declaring enum which conforms to Error Protocol:

enum CustomError: Error {
case error01
}

2- Declaring foo() as throwable function:

func foo() throws {
throw CustomError.error01
}

3- Declaring bar() as throwable function:

func bar() throws {
try foo()
}

Note that although bar() is throwable (throws), it does not contain throw, why? because it calls foo() (which is also a function that throws an error) with a try means that the throwing will -implicitly- goes to foo().

To make it more clear:

4- Implement test() function (Do-Catch):

func test() {
do {
try bar()
} catch {
print("\(error) has been caught!")
}
}

5- Calling test() function:

test() // error01 has been caught!

As you can see, bar() automatically throws error, which is referring to foo() function error throwing.

Swift pass error caught inside function

Just write

func anotherMethod() throws {
try someMethod()
}

then the error will be handed over.

Swift 3 - do-catch and throw

If you want to substitute the error thrown by convert()
by another error then call convert() in a local do/catch context.
The outer do/catch is not needed because
a throwing function "automatically" propagates errors up
to the caller (compare How to pass an Error up the stack trace in Swift).

public func myFunc() throws
{
let obj: Any // or whatever type convert() returns
do {
obj = try convert(param: 42)
} catch {
throw MyError.ConversionFailed
}
// work with obj...
if obj is Array {
// great, continue working with obj...
} else {
throw MyError.NotAnArray
}
}

How to call throw in nested non-throwable closure?

If you can't change the function getOptionalConfigurations then you can't throw from inside function because nothing will process the error that you throw.

But if you want to throw the error from the outer function without changing the existing architecture I can propose only a very bad solution:

func retrieveConfigurations(_ completion:@escaping (([String]?) throws -> Void)) throws {
let d = DispatchGroup()
var errorToThrow: Error?

d.enter()
getOptionalConfigurations { (configurations: [String]?, error: Error?) in
do {
try completion(configurations)
d.leave()
} catch {
errorToThrow = error
d.leave()
}
}

d.wait(timeout: .now() + 10)

if let error = errorToThrow {
throw error
}
}

That's bad because if getOptionalConfigurations is executed async then current thread will have to wait for it's completion. I also added timeout for 10 seconds. You can change that to infinity which will make it even worse or just change the number of seconds.

inout parameter in Swift

The error should be at the top of the stack trace:

Simultaneous accesses to 0x109fac098, but modification requires exclusive access.

When you pass char1 as a inout parameter to changeChar it is a memory violation to access char1 in any other way until that function returns.

For full details, see SE-176 Enforce Exclusive Access to Memory which added this restriction in Swift 4.

Swift return or throw

I don't think you can use null coalesce in a return statement. However, you can do something like this

guard let res = calcSomething() else { throw err.invalidSomething }
return res


Related Topics



Leave a reply



Submit