# Errors

There are times when, for some reason, you will not be able to finish some process. No matter the reason, could be a violation of preconditions or some error with the state, in these cases, it would be ideal to not crash the app, but provide some helpful errors to explain what went (or is going) wrong.

### Designing Errors

There are no built in errors in Swift. You can use `assert(_: Bool)` or `fatalError(_:)`, but this doesn't really count. We can make any type an `Error` by adopting the `Error` protocol–no extra work needed! Generally speaking, we want to list all of the potential errors, which means you should usually be working with enums. If you need more information and don't want to use enums with associated values, you can store an enum as a member inside a larger object/value. But generally speaking, enums are the best practice.

We can imagine when working with networking, that the following issues may arise:

```swift
enum NetworkError {
    case invalidURL(String)
    case serverError
    case invalidData
    case poorConnection
}
```

Note: you'd normally use the `URL` type, but this is only for demonstration purposes, so do not use this XD

### Raising Errors

Now that we have built an error, raising them is super easy! Just create an instance, and write `throw` \<error>. With the example above, we could do:

```swift
throw NetworkError.serverError
```

### Marking as Error-Prone

As with everything in Swift, we need to be explicit about what is going on. Thus, the potential for errors becomes part of types. If a function can raise an error, we say that it `throws`. We write the `throws` right after the parameters of a function, but before the `->` for return type if there is one.

```swift
func network() throws -> Data {
    ...
}
```

### Handling Errors

If a process is marked as throwing, you will need to acknowledge the error in how you handle it. We have three methods to deal with errors, but they can be slightly confusing because they all use the `try` keyword.

#### Default Try

This is probably pretty similar to how you have handled errors in your other languages. We use a do-catch block. Every time there is a potential error in a do block we must use some try.

```swift
do {
    let someData = try network()
    ...
    let someMoreData = try network()
    ...
}
...
```

The catch, where you actually handle the error, is very flexible. We can categorize instructions by the type of error. You can think of this almost like a switch block, except you don't need to handle all of the potential cases (because there could be so many types of errors).

#### Catching Enum Cases

We can catch a specific enum case just by using `catch` followed by the case:

```swift
... } catch NetworkError.serverError {}
```

You can also use a let-statement to bind an associated value.

```swift
... } catch NetworkError.invalidURL(let url) {}
```

#### Catching Types

If you do not care about the specific information in an error, just about its type then you can use the `is` keyword:

```swift
... } catch is NetworkError { ... }
```

#### Additional Classification of Types

If you want a certain block to execute given a type, but you actually need further differentiation (and could not get that with the above methods) you can do a conditional assignment. I think of this as a `where` clause.

```swift
... } catch let e as NetworkError {
    switch e { ... }
}
```

I'm just using switch as an example–you can do whatever you want.

You may gravitate towards this option if you have chosen to use a class or struct for your error.

#### Default&#x20;

&#x20;In the case where you don't catch an error, it will automatically be raised (i.e. you didn't handle it, so it will run free and stop your program). As with switches, there is a default case. Just write catch. This will assign the error to the identifier `error`:

```swift
... catch {
    // error: Error = ...
}
```

### try?

Catching can be a lot. What if you only want to do something if no error is thrown and just ignore any other case? As the name implies, `try?` convert our results into optionals! If there is no error, it returns an optional and otherwise a `nil` value. In this case, we don't need a do-catch block.

```swift
let myData: Data? = try? network()
```

### try!

As you may have guessed, this is the force-unwrapped version of errors. We are guaranteeing that whatever we are doing, even though it is marked as `throws`, will never raise an error. We are so convinced of this fact, that if we are wrong, we are okay with the program crashing. You do not need a do-catch block.

```swift
let myData: Data = try! network()
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ios-course.cornellappdev.com/resources/swift-foundations/errors.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
