【问题标题】:Is there anything like a Java enum in Objective-C?Objective-C 中有没有类似 Java 枚举的东西?
【发布时间】:2012-02-12 06:52:07
【问题描述】:

我在 Objective-C 中有一种情况,Java 风格的枚举会很有帮助。我有一组图层类型,每个图层都有自己关联的持久性值(以秒为单位存储)。我想将这些层类型保留在一个枚举中,因为它们太相似而无法组成单独的类,如下所示:

typedef enum {
    ExplosionLayerType,
    FireworkLayerType,
    FireLayerType,
    FireJetLayerType
} FXLayerType;

在 Java 中,我可以轻松地将这两个值与以下内容相关联:

public enum FXLayerType {
    Explosion(3),
    Firework(6),
    Fire(7),
    FireJet(-1);

    private int persistence;

    FXLayerType(int persistence) {
        this.persistence = persistence;
    }
}

是否有一种简单的方法可以在 Objective-C 中创建类似这样的轻量级类,或者需要求助于更原始的方法?

编辑:

很多人建议做这样的事情:

typedef enum {
    ExplosionLayerType = 3,
    FireworkLayerType = 6
} FXLayerType;

这对我不起作用,因为我可能有这样的东西(Java 风格的枚举):

Explosion(3),
Firework(6),
Dust(3);

在 Java 中,Dust 和 Explosion 将被视为唯一值,但使用 C 枚举直接赋值会将它们视为完全相同。

【问题讨论】:

  • 是否可以将 int 值用作枚举值(有关自定义枚举值的示例,请参阅 this answer)?
  • @perelman:嗯,我不知道这个功能。这绝对是可能的,虽然感觉有点骇人听闻。
  • @perelman:再想一想,不,我不能,因为多个层类型可能共享相同的持久性值,但必须保持唯一。
  • @JakeKing 究竟是如何工作的?当值 3 从持久存储反序列化时,你怎么知道它应该变成 DustLayerType 而不是 ExplosionLayerType?
  • @hamstergene:持久性值与持久性存储无关,如果令人困惑,抱歉。这只是它应该在我的游戏中“存活”多长时间。

标签: objective-c enums


【解决方案1】:

如果您只需要一个原始容器来存储类型和值,请考虑以下方法:

typedef struct FXLayerValue {
  FXLayerType type;
  int value;
} FXLayerValue;

再一次,如果事情变得复杂或更好地动态处理,类层次结构可能值得考虑。警告:如果您要保存和/或创建大量对象,则 objc 类型将过度杀伤并降低性能。

不幸的是,我的 Java-Fu 不足以了解枚举的所有语言差异。

【讨论】:

    【解决方案2】:

    为了模拟 Java 枚举,我们需要一些可比较的东西(可以是 == 等的操作数),它可以有字段,并且是轻量级的。这暗示了结构,以及可选的指向结构的指针。这是后者的一个例子:

    FXLayerType.h:

    typedef const struct { int persistence; } FXLayerType;
    
    extern FXLayerType * const LayerTypeExplosion;
    extern FXLayerType * const LayerTypeFirework;
    extern FXLayerType * const LayerTypeDust;
    

    FXLayerType.m:

    #import "FXLayerType.h"
    
    const FXLayerType _LayerTypeExplosion = { 3 };
    const FXLayerType _LayerTypeFirework = { 6 };
    const FXLayerType _LayerTypeDust = { 3 };
    
    FXLayerType * const LayerTypeExplosion = &_LayerTypeExplosion;
    FXLayerType * const LayerTypeFirework = &_LayerTypeFirework;
    FXLayerType * const LayerTypeDust = &_LayerTypeDust;
    

    所以FXLayerType 本身是一个常量结构,而与 Obj-C 对象一样,我们总是使用指向这些结构的指针。该实现创建了 3 个常量结构和 3 个指向它们的常量指针。

    我们现在可以编写如下代码:

    FXLayerType *a, *b;
    a = LayerTypeDust;
    b = LayerTypeExplosion;
    
    NSLog(@"%d, %d\n", a == b, a->persistence == b->persistence);
    

    将输出“0, 1” - a 和 b 是不同的枚举 (0) 但具有相同的持久性 (1)。注意这里a和b不是常量指针,只有枚举“字面量”被定义为常量。

    正如所写的那样,它的缺点是您不能在枚举值上使用switch。但是,如果需要,只需添加第二个字段,例如 tag,并使用真正的枚举使用唯一值初始化它,例如 FXLayerStyleTag。如果您愿意始终比较标签(例如a.tag ==b.tag`),您也可以删除间接。这给了你:

    FXLayerType.h:

    typedef enum { ExplosionTag, FireworkTag, DustTag } FXLayerTypeTag;
    typedef struct { FXLayerTypeTag tag; int persistence; } FXLayerType;
    
    extern const FXLayerType LayerTypeExplosion;
    extern const FXLayerType LayerTypeFirework;
    extern const FXLayerType LayerTypeDust;
    

    FXLayerType.m:

    #import "FXLayerType.h"
    
    const FXLayerType LayerTypeExplosion = { ExplosionTag, 3 };
    const FXLayerType LayerTypeFirework = { FireworkTag, 6 };
    const FXLayerType LayerTypeDust = { DustTag, 3 };
    

    用途:

    FXLayerType a, b;
    a = LayerTypeDust;
    b = LayerTypeExplosion;
    
    NSLog(@"%d, %d\n", a.tag == b.tag, a.persistence == b.persistence);
    

    这两种设计的不同之处在于第一次传递指针,而第二次传递可能更大的结构。您可以将它们组合起来,以获得 switchable 基于指针的枚举 - 这留作练习!

    这两种设计还有一个(缺点)优点是枚举“文字”的数量可以随时扩展。

    【讨论】:

      【解决方案3】:

      实际上,您可以为 C 中的枚举键赋值,因为它们只是整数:

      typedef enum {
        LayerTypeExplosion = 3,
        LayerTypeFirework = 6,
        LayerTypeFire = 7,
        LayerTypeFireJet = -1
      } FXLayerType;
      

      您可以将它们简单地用作受限的值集,以分配给FXLayerType 类型的变量。

      FXLayerType myLayerType = LayerTypeFirework;
      NSLog(@"Value of myLayerType = %i", myLayerType);
      // =>  "Value of myLayerType = 6"
      

      【讨论】:

      • 引用我的另一条评论:这对我不起作用,因为类型必须保持唯一。在 Java 中,如果我声明了两个值,ExplosionLayerType(3) 和 DustLayerType(3),它们将共享相同的持久性值,但将保持唯一。这将以同样的方式对待它们。
      【解决方案4】:

      这不是 100% 等效的,但这可能是您可以在 Objective-C 中采用的一种方法。基本上,创建几个类级别的便捷方法来构建 FXLayerType 的各种配置。

      @interface FXLayerType
      {
      @private
      int persistence;
      }
      
      + (FXLayerType*)fireworkLayerType;
      + (FXLayerType*)explosionLayerType;
      + (FXLayerType*)jetLayerType;
      
      @end
      
      @implementation FXLayerType
      
      + (FXLayerType*)explosionLayerTypeWithPersistence:(int)persistence
      {
         FXLayerType* layerType = [[FXLayerType new] autorelease];
         layerType->persistence = persistence;
         return layerType;
      }
      
      + (FXLayerType*)explosionLayerType
      {
         return [self explosionLayerTypeWithPersistence:3];
      }
      
      + (FXLayerType*)fireworkLayerType
      {
         return [self explosionLayerTypeWithPersistence:6];
      }
      
      + (FXLayerType*)jetLayerType
      {
         return [self explosionLayerTypeWithPersistence:-1];
      }
      
      @end
      

      用法:

      FXLayerType* aJetLayerType = [FXLayerType jetLayerType];
      

      【讨论】:

      • 这对我不起作用,因为类型必须保持唯一。在 Java 中,如果我声明了两个值,ExplosionLayerType(3) 和 DustLayerType(3),它们将共享相同的持久性值,但仍然是唯一的。这将以同样的方式对待它们。
      【解决方案5】:

      我最近使用了 j2objc 格式的枚举。它工作得很好。此外,如果您尝试直接从 java 对象映射,您可以自动生成枚举。

      https://code.google.com/p/j2objc/wiki/Enums

      但是,我确实从“枚举”中删除了 j2objc 特定类。我不想要额外的依赖。

      【讨论】:

        【解决方案6】:

        基于结构的答案表面上看起来不错,但当您尝试将 Objective-C 对象添加到结构中时会失败。鉴于此限制,真正模拟 Java 风格的枚举可能比它的价值更多。

        【讨论】:

          猜你喜欢
          • 2017-02-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多