自上而下的iOS错误架构

关于iOS生态系统中的错误处理的文章并不多,即使对于每个应用程序来说,这似乎都不是简单而实质的组成部分。 今天,我希望解决这个问题,并提出我的解决方案,以减少iOS应用程序中的破坏性错误处理。

初始状态

为了确保我们在同一个页面上,通过错误我将表示一个符合Swift的Error类型的实例,并且错误处理是对此的一种反应。 这些错误可能以同步方式(磁盘操作,无效参数)或异步方式 (没有Internet连接,会话令牌无效等)到达。 显然,由于Swift的标准docatch结构,第一组更容易处理。 通常,简单的自下而上的过程就足够了,其中错误会中断执行并自动将其传递给调用方。 如果您具有带有完成处理程序的异步API,则开发人员可以自由选择众多技术(通常也遵循自下而上的模型)(提及Promise或RX流)。 通常,自下而上意味着如果我们无法完全处理错误,则会将错误传播到父层。

我发现,在许多情况下,自下而上的方法不是最佳方法,当错误必须遍历许多层以达到能够消耗它的目的时,就会导致沮丧。 举一个例子,假设APIClient收到401 Unauthorised HTTP响应,并且您的应用应返回到初始登录屏幕。 您是否熟悉ViewModel中的完成处理程序是否能够处理特定错误,是否不将其传递给其Flow Coordinator,然后将其传递给父级Flow Coordinator以最终到达通用位置,是否听起来很熟悉?您指示导航控制器移回根目录。 它最终以一个代码打开,该代码可以广泛地打开错误,例如:

如果您为不同元素之间的通信选择了委托机制,则委托协议可能会开始膨胀-每个协调器都应包括其嵌套子代的错误事件。 我观察到,在许多应用程序中,树的上层只能处理某些特定错误(例如会话无效或不受支持的API版本),并且在下面是一个聚集点,所有错误均以警报视图或类似形式呈现给UI。 )。 因此,我建议不要从底层开始,而是还原传播顺序,并从顶层开始并仅在父层无法处理时将其向下传递。

请注意,在根元素中,我们获得了应用程序中所有错误的单个聚集点,这对于分析目的可能是有用的。

因此,让我们将错误处理过程分为两个阶段:

  • 阶段1:将事件传播到其父对象(无条件)
  • 阶段2:逐层向下传播事件,找到可以处理事件的事件

这样的过程并不是一个全新的想法,例如JavaScript使用了一种非常类似的技术,称为冒泡事件委托,将触摸事件分配给DOM元素。

协议定义

实现自上而下的错误处理体系结构并不是一项艰巨的任务。 让我向您展示,您可以使用面向扩展开放协议的面向通用协议的解决方案轻松地在50行代码中实现它。

出于本文的目的,我将使用受Swift关键字列表( catchthrowfinally )启发的函数名称。 尽管你们中的一些人可能会觉得有点争议,但我相信这样的类比有助于理解它。

我们将定义唯一的协议ErrorHandleable ,它将用作错误处理树中的节点。 每个实例都保留对第1阶段传播中使用的父层的引用,并封装第2阶段中使用的通用闭包( HandleAction ),该闭包决定是否应将其填充(引发错误)。

此外,没有什么可以阻止在操作块中重写错误。 只需抛出一个全新的错误(例如在errorHandler#1中),所有下面的层将观察到已修改的错误。 但是,请记住,强大的力量伴随着巨大的责任,请谨慎使用此功能…

该协议API非常通用,因此我们可以添加一些扩展以方便使用:

  1. 约束将错误捕获为通用类型并透明地传递所有其他类型: