【问题标题】:State Machine - Is enum the choice for states?状态机 - 枚举是状态的选择吗?
【发布时间】:2011-10-28 10:04:30
【问题描述】:

我希望将类静态变量作为状态,但 Objective C 不允许这样做

我为状态类尝试了+(int)LOOPING_STATE,但它会失败

switch (myCurrentState) {
case [STATE_CLASS LOOPING_STATE]:   <== received an error of "expression can't be put here"
return;
}

枚举通常是编写状态代码的选择吗?

还有其他选项吗?应该在什么条件下使用这些选项?

提前致谢。

【问题讨论】:

    标签: objective-c enums state


    【解决方案1】:

    这与 Objective-C 关系不大,但更多的是与 Objective-C 中的 C 相关。一般来说,使用枚举来表示状态机的状态应该优于普通整数。

    不能在 switch 中使用类的原因是 switch 语句的 case 标签中使用的表达式的值需要在编译时知道。假设[STATE_CLASS LOOPING_STATE] 是一个类方法的调用,编译器在编译时无法安全地知道该表达式的结果,因此会拒绝生成 switch 语句。

    为什么编译器需要在编译时知道用于 case 标签的表达式的结果? switch 语句背后的想法是比一系列语义等效的 if/else if 块更有效。这是通过将 switch 语句转换为具有无条件跳转的调度表来实现的,而 if/else if 解决方案需要大量条件跳转。很容易猜到,条件跳转与现代流水线 CPU 设计根本不一致,因为它们可能会导致整个流水线被刷新。 (现代 CPU 试图用复杂的分支预测来弥补,但如果我们能完全避免这个问题会更好,对吧?)

    但是,首先要做到正确,其次才是快速。

    【讨论】:

    • 感谢您的解释。我讨厌枚举定义的全局常量,有没有办法将状态常量放在一个类下?还是有其他选择可以做我想做的事?谢谢!
    • 在状态机的标头中声明一个枚举应该没问题,毕竟状态的数量无论如何都应该是有限的。我认为枚举在全局范围内定义这些常量没有问题(毕竟,您只对符号感兴趣,而不是值)。
    【解决方案2】:

    如果这个状态机需要快速,枚举是要走的路。但是,如果您想要一种面向对象的方式来执行此操作,则每个状态的功能将是状态对象本身的方法。因此,您将完全取消 switch/if 语句。你的状态机循环看起来像这样:

    -(void) run
    {
        State* currentState;
    
        currentState = [self startState];
        while (currentState != [self stopState])
        {
            currentState = [currentState transitionWitInput: inputs 
                                                    actions: actions];
        }
    }
    

    inputs 是状态转换的输入数据,actions 是块或选择器或NSInvocation 或告诉状态在转换期间要做什么的东西。

    【讨论】:

      猜你喜欢
      • 2010-10-07
      • 1970-01-01
      • 2018-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      相关资源
      最近更新 更多