Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: if a do return try fails does catch execute

Tags:

return

swift

I am working on a piece of code that is going to fetch an array of NSManagedObjects from CoreData. When using a do catch statement in my code it doesn't seem right to do it this way, but it is the simplest way I can write this line of code.

In any other scenario when you use the return statement you are jumping out of the current function you are in. And you can be assured that no other code in your function will execute past the return statement. I am wondering if the same applies to Swift's do catch paradigm.

class func getAll() -> [MMNotification] {
    let context = appDelegate.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<MMNotification>(entityName: "MMNotification")
    do {
        return try context.fetch(fetchRequest)
    }
    catch {
        // Will this 'catch' if the try fails, 
        // even if we said we are 'return'ing right before the 'try'?
        return []
    }
}

Here I am fetching a list of notifications stored in CoreData. In the do block you can see the line of code in question.

QUESTION

Will the catch block execute if the try fails after already stating that the function should return?

like image 375
Brandon A Avatar asked Apr 28 '17 22:04

Brandon A


3 Answers

What you have should work as expected. Basically what happens is if a throw occurs at any time within a do, the catch is called and any code after the throw will not be executed.

like image 118
GetSwifty Avatar answered Feb 08 '23 16:02

GetSwifty


Yes, the catch block will execute if the try in return try fails. The return will not happen.

Here's a little code to prove it to yourself. Paste it into a new playground to try it out.

import UIKit

let shouldFail = true

enum DemoError:Error {
    case shouldFail
}

func failableGetter() throws -> String {
    if shouldFail { throw DemoError.shouldFail }
    return "Succeeded"
}

func fetchInfo() -> String {
    do {
        return try failableGetter()
    } catch {
        return "Failed"
    }
}

print(fetchInfo()) // "Failed" or "Succeeded" depending on shouldFail

When shouldFail is true, the failableGetter() throws an error and the do-catch in fetchInfo() skips to the catch section before returning.

When shouldFail is false, the failableGetter() doesn't fail and fetchInfo() returns the result.

like image 28
Robert Avatar answered Feb 08 '23 15:02

Robert


Adding to this answer. Scope matters a bit here. Code inside the do block code after a throw will NOT be executed. However, code further down outside of the scope of the do block will be executed. I made a simple playground you can run to see for yourself.

import Foundation

let error = NSError(domain: "", code: 123, userInfo: [NSLocalizedDescriptionKey: "My error"])

func functionThatAlwaysThrows() throws {
    throw(error)
}

func myFunction() {
    do {
        try functionThatAlwaysThrows()

        // This will never print
        print("Continuing after throw inside do scope")
    } catch let err {
        print("Caught Error: \(err.localizedDescription)")
    }

    // This will always print
    print("Continuing after throw outside do scope")
}

Output:

Caught Error: My error
Continuing after throw outside do scope

If you want more information on Error handling you can take a look at the docs

like image 41
DoesData Avatar answered Feb 08 '23 16:02

DoesData