文章

在 App 中维护状态

利用枚举捕捉和跟踪 App 的状态。

概览

有效管理状态是 App 开发的一个重要部分;状态是用于跟踪 App 当下使用情况的数据位。由于枚举定义有限数量的状态,并可以将关联值与每个状态捆绑,因此你可以用枚举来为 App 的状态及其内部流程建模。

使用枚举捕捉状态

以一个需要用户登录账户的 App 为例。首次打开该 App 时,用户是未知的,因此该 App 的状态可以称为 unregistered。在用户注册或登录账户后,状态为 logged in。在闲置一定时间后,用户会话可能会过期,使 App 进入 session expired 状态。

你可以使用枚举来指定 App 所需的确切状态。这种方法定义一个 App 类,其嵌套的 State 枚举仅包含你需要的具体状态:

class App {
    enum State {
        case unregistered
        case loggedIn(User)
        case sessionExpired(User)
    }
  
    var state: State = .unregistered
  
    // ...
}

在这个模型中,每个状态用一个具有匹配名称的 case 来表示。loggedInsessionExpired case 都包含用户作为关联值,而 unregistered case 不包含关联值。在更新 App 的状态时,不管具体转换为何,都只有一个变量 (state) 需要修改。

示意图中显示 App 的不同状态:unregistered、logged in 和 session expired。

不要将状态分散到多个变量

在为 App 的状态建模时,也可以组合使用多个不同的变量来存放状态和所需数据,但不建议这么做。

在这个模型中,App 定义了两个变量:一个是用于储存用户信息的可选 user,另一个是名为 sessionExpired 的布尔值。用户没有登录时,user 变量为 nil;用户登录后,该变量便具有值。sessionExpired 变量的初始值是 false,在会话过期时设为 true。三个状态通过两个变量的不同组合来捕捉。

由于几种原因,使用这种方法容易出错;它可能会导致错误,也更加难以推断你的代码:

  • 对于状态的每次变化,你需要同时更新 usersessionExpired

  • 如果 App 的未来变化需要增加一个状态,你需要在每个现有状态变化中更新一个额外的变量。

  • 这两个变量还有一个未使用的组合;尽管该组合并没有对应的状态,但可以将 user 设为 nil 并将 sessionExpired 设为 true

另请参阅

数据流和控制流

在使用闭包时防止时序问题

了解对闭包的不同 API 调用可能对你的 App 造成怎样的影响。