🥱 Less do ... try ... catch clutter.
- ⛔️ No more long nested do...try...catch blocks.
- 🆗 Validate input easily.
- 🏷 Categorize errors.
- 🎁 Unwrap optinals in more intuitive way.
old way:
func parse(url: String) throws -> String {
guard let url = URL(string: url) else {
throw ParserError.invalidURL
}
do {
return try String(contentsOf: url)
} catch {
throw ParserError.invalidWebpage
}
}
The new way:
func parse(url: String) throws -> String {
guard let url = URL(string: url) else {
throw ParserError.invalidURL
}
return try execute(String(contentsOf: url),
orThrow: Error.invalidWebpage)
}
execute
method has three overloads:
execute( _: ,orThrow:)
execute( _: ,errorTransform:)
execute( _: ,orCaptureError:)
It is common to find yourself doing this:
func signup(user: User) {
guard user.username.count >= 3 else {
errorLabel.text = "Username must have at least 3 characters"
return
}
guard user.password.count >= 7 else {
errorLabel.text = "Password must have at least 7 characters"
return
}
// Additional validation like email ...etc
...
authService.signup(user: user) { result in
...
}
}
The validation logic can end up growing much quicker than we might expect so Validator
to rescue.
we can simply add our custom validation logic by extending Validator
like follows:
extension Validator where Value == String {
static var password: Validator {
return Validator { string in
try validate(
string.count >= 7,
errorMessage: "Password must contain min 7 characters"
)
// you can add more logig here...
try validate(
string.uppercased() != string,
errorMessage: "Password must contain a lowercased character"
)
}
}
static var username: Validator {
return Validator { string in
try validate(string.count >= 3, errorMessage: "Username must have at least 3 characters")
}
}
}
Then we can simplify our signup method using the brand new valiator
func signup(user: User) throws {
try validate(user.username, using: .username)
try validate(user.password, using: .password)
authService.signup(user: user) { result in
...
}
}
now call the function
try! execute(signup(user: user)) {
self.errorLabel.text = $0.localizedDescription
}
Any Error
type conforms to this protocol has to implement category
property of type ErrorCategory
example:
enum NetworkError: Error {
case noInternetConnection
case decodingFailure
case notAuthorized
}
extension NetworkError: CategorizedError {
var category: ErrorCategory {
switch self {
case .noInternetConnection:
return .retryable
case .decodingFailure:
return .notRetryable
case .notAuthorized:
return .requiresLogin
}
}
}
now we can easily for example show or hide a retry button according to the error type.
func handle(error: Error) {
// do other stuff
switch error.resolveCategory() {
case .retryable:
break
case .notRetryable:
retryButton.isHidden = true
case .requiresLogin:
performLogin()
}
}
ex:
var path: String?
...
func save() throws {
let path = path.orThrow(Error.invalidPath)
}
ErrorUtils
is available through CocoaPods. To install
it, simply add the following line to your Podfile:
pod 'ErrorUtils'
Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
To integrate ErrorUtils into your Xcode project using Carthage, specify it in your Cartfile
:
github "engali94/ErrorUtils"
Run carthage update
to build the framework and drag the built ErrorUtils.framework
into your Xcode project.
On your application targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase” and add the Framework path as mentioned in Carthage Getting started Step 4, 5 and 6
To integrate using Apple's Swift Package Manager, add the following as a dependency to your Package.swift
:
dependencies: [
.package(url: "https://github.com/engali94/ErrorUtils.git", from: "1.0.0")
]
Alternatively navigate to your Xcode project, select Swift Packages
and click the +
icon to search for ErrorUtils
.
If you prefer not to use any of the aforementioned dependency managers, you can integrate ErrorUtils
into your project manually. Simply drag the Sources
Folder into your Xcode project.
Contributions are very welcome 🙌
Most of the work done here is inspired by Swiftbysundell articles.
ErrorUtils is released under the MIT license. See LICENSE for more information.