Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch any error, specially unexpectedly found nil in swift

Tags:

swift

How can I catch any error, and I mean any type, including fatal errors, exceptions, any type...
in other languages we would use try, catch, but the do, catch doesn't do the trick when it's wrapping nil values. but why? really why?

like image 730
Mohsen Shakiba Avatar asked Jan 26 '16 05:01

Mohsen Shakiba


People also ask

How do you solve unexpectedly found nil while unwrapping an optional value?

99% of the time the above error is caused by a force-unwrapped optional that is nil. You can fix it by avoiding it becomes nil, which is sometimes not possible, so then you use optional binding or optional chaining. Avoid using implicitly unwrapped optionals when you can, unless you have a specific need to use it.

How do I capture a fatal error in Swift?

You are not supposed to catch fatalerror. It indicates a programming error. You don't catch programming errors, you fix your code. The crash is intentional and it is intentional that you cannot stop it.

Do catch error Swift?

You use a do - catch statement to handle errors by running a block of code. If an error is thrown by the code in the do clause, it's matched against the catch clauses to determine which one of them can handle the error.

What kind of error occurs when you force unwrap an optional that contains nil?

It's called implicitly unwrapped since Swift force unwraps it every time. The drawback of this is same as forced unwrapping - if the value is nil when accessing, it leads to a fatal error. Similar to optionals, optional binding and optional chaining can also be used for implicitly unwrapped optionals.


3 Answers

If I need to unwrap many optional values, for example when working with collections of Any values, it's not conveniently to write multiple guard let or if let statements. Instead, I'm using do-try-catch to handle nil. To achieve this, I'm using this simple unwrap snippet:

public struct UnwrapError<T> : Error, CustomStringConvertible {
    let optional: T?

    public var description: String {
        return "Found nil while unwrapping \(String(describing: optional))!"
    }
}


func unwrap<T>(_ optional: T?) throws -> T {
    if let real = optional {
        return real
    } else {
        throw UnwrapError(optional: optional)
    }
}

Usage:

do {
    isAdsEnabled = try unwrap(dictionary["isAdsEnabled"] as? Bool)
    // Unwrap other values...
} catch _ {
    return nil
}
like image 193
kelin Avatar answered Sep 17 '22 16:09

kelin


Unfortunately, that doesn't exist in swift.

You can catch errors that are thrown by a function like this:

do {
   let outcome = try myThrowingFunction()
} catch Error.SomeError {
   //do stuff
} catch {
  // other errors
}

or ignore thrown errors and just continue like this:

let outcome = try? myThrowingFunction()

but catching an unforeseen crash is not possible

like image 42
Daniel Avatar answered Sep 21 '22 16:09

Daniel


You use a do-catch statement to handle errors by running a block of code. If an error is thrown by the code in the do clause, it is matched against the catch clauses to determine which one of them can handle the error.

You use try? to handle an error by converting it to an optional value. If an error is thrown while evaluating the try? expression, the value of the expression is nil. For example, in the following code x and y have the same value and behavior:

func someThrowingFunction() throws -> Int {
    // ...
}

let myValue1 = try? someThrowingFunction()

let myValue2: Int?
do {
    myValue2 = try someThrowingFunction()
} catch {
    myValue2 = nil
}

If someThrowingFunction() throws an error, the value of myValue1 and myValue2 is nil. Otherwise, the value of myValue1 and myValue2 is the value that the function returned. Note that myValue1 and myValue2 are an optional of whatever type someThrowingFunction() returns. Here the function returns an integer, so myValue1 and myValue2 are optional integers.

Using try? lets you write concise error handling code when you want to handle all errors in the same way. For example, the following code uses several approaches to fetch data, or returns nil if all of the approaches fail

func fetchData() -> Data? {
    if let data = try? fetchDataFromDisk() { return data }
    if let data = try? fetchDataFromServer() { return data }
 return nil
}

if you want to check nil value , you can also use like this :-

var myValue: Int?


if let checkValue:Int = myValue {
  // run this when checkValue has a value which is not ni
}  
like image 37
Chathuranga Silva Avatar answered Sep 19 '22 16:09

Chathuranga Silva