SwiftErrorHandler 5.0.4

SwiftErrorHandler 5.0.4

Stefan Renne 维护。



  • Stefan Renne

SwiftErrorHandler

Swift 5.0 Travis Status Maintainability CocoaPods Version Badge Carthage compatible License Badge Platform

SwiftErrorHandler 允许使用少量代码和易于记忆的流畅 API 表达复杂错误处理逻辑。

安装

CocoaPods

pod 'SwiftErrorHandler', '~> 5.0'

Carthage

github "stefanrenne/SwiftErrorHandler" ~> 5.0

Swift 包管理器 (SPM)

import PackageDescription

let package = Package(
  name: "My App",
    dependencies: [
      .package(url: "https://github.com/stefanrenne/SwiftErrorHandler.git", from: "5.0.0")
    ]
)

使用说明

假设我们正在构建一个基于账户的iOS应用,该应用在网络层可能会抛出错误。

我们需要

一次设置默认ErrorHandler

默认ErrorHandler将包含你不想重复的错误处理逻辑,这些逻辑在应用程序中是通用的。你可以创建一个工厂来创建它,这样你就可以从应用程序的任何位置获取具有通用处理逻辑的新实例。

extension ErrorHandler {
  class func `default`(for view: ErrorHandlerView) -> ErrorHandler {
    return ErrorHandler(for: view)
      .on(error: .code(NSURLErrorTimedOut), then: .present(alert: ConfirmableAlert(title: "Timeout occurred", confirmTitle: "Retry", confirmAction: { error in print("retry network call") })))
      .on(error: .type(NetworkError.noInternet), then: .present(alert: ConfirmableAlert(title: "Did you turn off the internet?", confirmTitle: "No")))
      .on(error: .type(NetworkError.logout), then: .present(alert: RejectableAlert(title: "Are you sure you want to logout?", confirmTitle: "Yes", rejectTitle: "No")))
      .always(.perform(action: AnalyticsService.track))
      .onNoMatch(.present(alert: ConfirmableAlert(title: "Something went wrong", confirmTitle: "Ok")))
    }
}

使用默认处理程序处理常见情况

通常,默认处理程序知道的案例将足够好。

do {
  try saveStatus()
} catch {
  ErrorHandler.default(for: self).handle(error: error)
}

当需要时定制错误处理器。

在可用额外上下文的情况下,可以添加更多案例或覆盖已经提供的案例。

例如,在一个LoginViewController中

class LoginViewController: UIViewController {
    
  private lazy var errorHandler = ErrorHandler.default(for: self)
    .on(error: .type(NetworkError.authenticate), then: .perform(action: startAuthentication))
        
  func performLogin() {
    do {
      try login()
    } catch {
      errorHandler.handle(error: error)
    }
  }
    
  private func startAuthentication(for error: Error, onCompleted: OnErrorHandled) {
    print("start authentication ...")
    onCompleted?()
    return true
  }      
}

额外:对RxSwift的支持

let errorHandler = ErrorHandler.default(for: self)
Observable<User>
  .error(NetworkError.authenticate)
  .subscribe(onNext: { result in
      print("User loggedin")
    },
    onError: errorHandler.handle)
  .disposed(by: disposeBag)

额外:对Result的支持

let errorHandler = ErrorHandler.default(for: self)
let result: Result<User, NetworkError> = .failure(NetworkError.authenticate)
let user: User? = result.get(onError: errorHandler)

自定义选项

错误操作的行为

  • 对特定错误执行操作

    errorHandler.on(error: .code(404), then: .present(Alert))

  • 在无法找到特定错误匹配器时执行操作

    errorHandler.onNoMatch(.present(Alert))

  • 所有错误需要执行的操作

    errorHandler.always(.perform(action: analyticsService.track))

错误匹配器

匹配特定错误类型

errorHandler.on(error: .type(NetworkError.authenticate), then: .doNothing)

匹配 NSError code

``errorHandler.on(error: .code(404), then: .doNothing)`

匹配 NSError domain

errorHandler.on(error: .domain("remote"), then: .doNothing)

自定义匹配

extension ErrorMatcher {
    static func onCustomMatch() -> ErrorMatcher {
        .init(matcher: { error in 
            ...
            return true 
        })
    }
}

.on(error: .onCustomMatch()), then: .doNothing)

错误处理

不做任何事情

它主要存在是为了让文档和单元测试更容易理解。

errorHandler.on(error: .code(404), then: .doNothing)

显示警报

警报将在ErrorHandler初始化时提供的视图中显示

errorHandler.on(error: .code(404), then: .present(alert: ErrorAlert))

默认情况下,您可以显示两种警报类型

  • ConfirmableAlert:一个只有一个操作按钮的警报
  • RejectableAlert:一个有两个操作按钮的警报

您想使用不同的警报吗?

  1. 创建一个符合ErrorAlert协议的结构体
  2. 实现构建自定义UIAlertController的函数 func build(for error: Error, onCompleted: OnErrorHandled) -> UIAlertController
  3. 确保在所有的UIAlertAction完成块中已执行可选的onCompleted完成块

自定义操作

唯一的限制就是你的想象力。

errorHandler.on(error: .code(404), then: .perform(action: CustomActionHandler))

CustomActionHandler提供Error和一个可选的需要在自定义操作完成后执行的onCompleted完成块。

在ViewController外部实现ErrorHandler

在大型应用程序中,最好在ViewController之外的其他类中实现ErrorHandler。为了使其工作,您需要提供一个视图,可以在其中显示警报。这可以通过符合ErrorHandlerView协议来实现。

public protocol ErrorHandlerView {
  func present(alert: UIAlertController)
}

extension UIViewController: ErrorHandlerView {
  public func present(alert: UIAlertController) {
    present(alert, animated: true, completion: nil)
  }
}

贡献?

使用 Swift 包管理器构建您的 xcode 项目

swift package generate-xcodeproj --xcconfig-overrides ./Sources/ios.xcconfig

在提交 PR 之前快速检查清单摘要

  • 🔎确保添加或更新了测试以适应您所做的更改。我们不接受任何没有测试的更改。在可能的情况下,添加测试以验证错误修复并防止未来的回归。
  • 📖检查您是否提供了 CHANGELOG 条目以记录您的更改(除了文档改进)
  • 👌验证测试是否通过
  • 👍推送它!

为什么?

在设计错误处理时,我们通常需要

  1. 一个用于 预期 错误的 默认 处理程序 // 例如网络、数据库错误等。
  2. 根据错误发生的 上下文 以自定义方式处理 特定 错误 // 例如上传文件时的网络错误,无效登录。
  3. 在每次错误时执行 不特定 的处理程序 // 例如将错误记录到 Fabric 或其他分析服务。
  4. 有一个针对 未知 错误的 通配符 处理程序 // 例如我们没有自定义处理程序的错误。
  5. 让我们的代码保持 DRY

Swift 有一个深思熟虑的错误处理模型,它平衡了方便(自动传播)和清晰度-安全性(类型传播标记传播)。因此,编译器会警告需要处理的事件,同时使错误传播和向上传递相对容易。

然而,即使在语言的这种帮助下,在一个相当大的应用程序中以临时方式实现上述目标也可能导致大量的 样板 代码,这是 繁琐 的编写和推理。因此,开发者通常会选择吞下错误或以相同的方式处理它们。

这个库通过提供定义灵活的错误处理规则和有观点的流畅 API 的抽象来解决这个问题。