You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ErrorKit makes error handling in Swift more intuitive. It reduces boilerplate while providing more insights. Helpful for users, fun for developers!
3
+
**ErrorKit** makes error handling in Swift more intuitive. It reduces boilerplate code while providing clearer insights. Helpful for users, fun for developers!
4
4
5
-
TODO: list all the advantages when using ErrorKit over Swift's native types
5
+
*TODO: Add a list of advantages of using ErrorKit over Swift’s native error handling types.*
6
6
7
-
## Why we are introducing the `Throwable` protocol to replace `Error`
7
+
---
8
8
9
-
### Confusing `Error` API
9
+
##Why We Introduced the `Throwable` Protocol to Replace `Error`
10
10
11
-
The `Error`type in Swift is a very simple protocol that has no requirements. But it has exactly one computed property we can call named `localizedDescription` which returns a text we can log or show users.
11
+
### The Confusing `Error`API
12
12
13
-
You might have written something like this, providing a `localizedDescription`:
13
+
Swift's `Error` protocol is simple – too simple. It has no requirements, but it offers one computed property, `localizedDescription`, which is often used to log errors or display messages to users.
14
+
15
+
Consider the following example where we provide a `localizedDescription` for an enum:
case .noConnectionToServer:"No connection to the server."
25
+
case .parsingFailed:"Data parsing failed."
27
26
}
28
27
}
29
28
}
30
29
```
31
30
32
-
But actually, this doesn't work. If we randomly throw an error and print it's`localizedDescription` like in this view:
31
+
You might expect this to work seamlessly, but it doesn’t. If we randomly throw an error and print its`localizedDescription`, like in the following SwiftUI view:
33
32
34
33
```swift
35
34
structContentView: View {
@@ -45,29 +44,40 @@ struct ContentView: View {
45
44
}
46
45
```
47
46
48
-
The console output is cryptic and not at all what we would expect: 😱
47
+
The console output will surprise you: 😱
49
48
50
49
```bash
51
50
Caught error with message: The operation couldn’t be completed. (ErrorKitDemo.NetworkError error 0.)
52
51
```
53
52
54
-
There is zero info about what error case was thrown – heck, not even the enum case name was provided, let alone our provided message! Why is that? That's because the Swift `Error` type is actually bridged to `NSError` which works entirely differently (with `domain`, `code`, and `userInfo`).
53
+
There’s no information about the specific error case. Not even the enum case name appears, let alone the custom message! Why? Because Swift’s `Error` protocol is bridged to `NSError`, which uses `domain`, `code`, and `userInfo` instead.
54
+
55
+
### The "Correct" Way: `LocalizedError`
56
+
57
+
The correct approach is to conform to `LocalizedError`, which defines the following optional properties:
55
58
56
-
The correct way in Swift to provide your own error type is actually to conform to `LocalizedError`! It has the following requirements: `errorDescription: String?`, `failureReason: String?`, `recoverySuggestion: String?`, and `helpAnchor: String?`.
59
+
- `errorDescription: String?
60
+
-`failureReason: String?`
61
+
-`recoverySuggestion: String?`
62
+
-`helpAnchor: String?`
57
63
58
-
But all of these are optional, so you won't get any build errors when writing your own error types, making it easy to forget providing a user-friendly message. And the only field that is being used for `localizedDescription` actually is `errorDescription`, the failure reason or recovery suggestions, for example, get completely ignored. And the help anchor is a legacy leftover from old macOS error dialogs, it's very uncommon nowadays.
64
+
However, since all of these properties are optional, you won’t get any compiler errors if you forget to implement them. Worse, only `errorDescription` affects `localizedDescription`. Fields like `failureReason` and `recoverySuggestion` are ignored, while `helpAnchor`is rarely used today.
59
65
60
-
All this makes `LocalizedError` confusing and unsafe to use. Which is why we provide our own protocol:
66
+
This makes `LocalizedError` both confusing and error-prone.
67
+
68
+
### The Solution: `Throwable`
69
+
70
+
To address these issues, **ErrorKit** introduces the `Throwable` protocol:
61
71
62
72
```swift
63
73
publicprotocolThrowable: LocalizedError {
64
74
var localizedDescription: String { get }
65
75
}
66
76
```
67
77
68
-
It is super simple and clear. We named it `Throwable`which is consistent with the`throw` keyword and has the common `able`ending used for protocols in Swift (like `Codable`, `Identifiable` and many others). And it actually requires a field and that field is named exactly like the `localizedDescription`we call when catching errors in Swift, making errors intuitive to write.
78
+
This protocol is simple and clear. It’s named `Throwable`to align with Swift’s`throw` keyword and follows Swift’s convention of using the `able`suffix (like `Codable` and `Identifiable`). Most importantly, it requires the `localizedDescription`property, ensuring your errors behave exactly as expected.
Now when printing`error.localizedDescription` we get exactly the message we expect! 🥳
96
+
When you print`error.localizedDescription`, you'll get exactly the message you expect! 🥳
87
97
88
-
But it doesn't end there. We know that not all apps are localized, and not all developer have the time to localize all their errors right away. So we even provide a shorter version that you can use in your first iteration if your cases have no parameters. Just provide raw values like so, making your error type definition even shorter while maintaining descriptive error message:
98
+
### Even Shorter Error Definitions
99
+
100
+
Not all apps are localized, and developers may not have time to provide localized descriptions immediately. To make error handling even simpler, `Throwable` allows you to define your error messages using raw values:
This approach eliminates boilerplate code while keeping the error definitions concise and descriptive.
110
+
111
+
### Summary
98
112
99
-
> We recommend conforming all your custom error types to `Throwable`rather than`Error` or `LocalizedError`. It has one requirement, `localizedDescription: String`, which will be exactly what you expect it to be.
113
+
> Conform your custom error types to `Throwable`instead of`Error` or `LocalizedError`. The `Throwable` protocol requires only `localizedDescription: String`, ensuring your error messages are exactly what you expect – no surprises.
0 commit comments