使用Swift枚举更安全,更易读的代码

如果您已经构建了一段时间的iOS应用程序,则可能已经编写了一些View Models。 在本文中,我们将以一个视图模型为例,说明如何使用Swift枚举编写更安全,更易读和更可扩展的代码。

在我们的示例中,我们将构建一个必须表示三个状态的视图模型:

  • 第一个状态是加载状态,表示在我们有任何内容要显示给用户之前正在进行的网络操作。 通常,向用户显示带有某种活动指示器的空白屏幕。
  • 第二种状态是项目(即产品)的同类列表。 内容加载后将显示此状态。
  • 第三状态是刷新状态,表示用户何时手动触发了正在显示的内容的刷新。 在这种状态下,我们希望继续显示以前加载的内容,但还向用户显示一些指示正在进行网络操作以获取新内容的指示。

我们可以构建一种表示这种情况的结构的方式如下:

  var viewModel:ViewModelstruct ViewModel { 
var isLoading:布尔
var isRefreshing:布尔
var content:[内容]?
}

乍一看似乎很好,但是仔细检查后,很明显,我们的视图模型具有我们实际上不需要的几种状态。 例如,将isLoadingisRefreshing都设为true并没有多大意义,它们应该是互斥的。

您可能会认为这很好,因为您知道这些标志应该互斥,并且可以确保每次将值分配给一个时都将反向赋给另一个。 可能会带来摩擦的地方是不具备该知识的人来对此代码进行一些更改。 仅仅通过查看View模型上的属性,他们就可以假设isLoadingisRefreshing可以同时为true ,或者当isLoadingtruecontent可以包含元素,这不是我们的意图。

用数学术语来表示,如果我们将content视为布尔值(我们有内容或没有内容),则我们的视图模型具有2³= 8种可能的状态,与我们预期的三种状态相反。

输入枚举

我们如何阐明和执行我们对视图模型的规则? 我们想要实现的是一个数据结构,其可能的状态恰好反映了我们视图的预期状态。 使用Swift枚举,我们可以这样做:

  var viewModel: ViewModel枚举ViewModel { 
装箱
装箱(内容:[内容])
案例刷新(内容:[内容])
}

查看此内容,我们可以清楚地看到我们的视图应具有三种状态:加载内容,显示内容和刷新内容(但仍显示先前加载的内容)。 这使初次查看此视图​​模型的人更容易了解确切的预期状态。

当我们需要与我们的视图模型进行交互时,以前的代码看起来像这样:

 如果viewModel.isLoading { 
//设置加载界面
}
否则,如果viewModel.isRefreshing {
//如果让content = viewModel.content {
用于内容中的项目{
//为现有内容设置UI
}
}
}
其他{
如果让content = viewModel.content {
用于内容中的项目{
//为现有内容设置UI
}
}
}

但是对于我们的枚举,它看起来像这样:

 切换viewModel { 
案例。加载:
//设置加载界面
案例。刷新(让内容):
//为内容中的项目设置刷新界面{
//为现有内容设置UI
}
案例.loaded(让内容):
用于内容中的项目{
//设置内容的UI
}
}
//如果我们向View Model枚举添加新案例,则此开关不会
//编译直到我们处理为止(这很好!)

使用枚举还允许编译器在向视图模型添加新状态时为我们做一些工作。 在原始示例中,我们将必须记住手动向状态处理代码中添加更多条件,但是对于枚举示例,编译器将强制我们的switch处理枚举的所有情况。


因此,重新审视我们最初的主张,这是否使我们的代码更安全? 我想是这样,因为我们有编译器让我们对处理所有View Model状态保持诚实,并且没有第一个示例中那样未使用或不一致的状态。

它使我们的代码更具可读性吗? 因为我们要做的就是通读枚举的实例以了解我们的视图模型的状态,而不是通读多个属性并了解它们之间的关系,所以我认为它具有。

它使我们的代码更具可扩展性吗? 我认为它具有作用,因为当我们想向视图模型添加新状态时,我们要做的就是向开关添加新的枚举实例和新的分支,而不是添加其他属性并进一步增加混乱的可能性我们的状态处理代码。


您对Swift枚举有何想法? 您觉得它们有用还是麻烦? 如果您有任何疑问,或者更好的是,我还可以通过其他方式给我@RowbotNZ鸣叫,以保持我的代码干净。

谢谢阅读!