Есть ли что-нибудь похожее на перечисление Java в Objective-C? - PullRequest
4 голосов
/ 12 февраля 2012

У меня есть ситуация в 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, или нужно будет прибегнуть к более примитивным методам?

EDIT:

Различные люди предлагали сделать что-то вроде этого:

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

Это не сработает для меня, поскольку у меня может быть что-то вроде этого (перечисление в стиле Java):

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

В Java Dust и Explosion будут обрабатываться как уникальные значения, но прямое присваивание с перечислениями C будет рассматривать их как абсолютно одинаковые.

Ответы [ 6 ]

2 голосов
/ 12 февраля 2012

Чтобы эмулировать перечисления 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 не являются константными указателями, только константы enum определены как константы.

Как написано, это имеет тот недостаток, что вы не можете 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);

Разница между этими двумя конструкциями заключается в том, что первые обводят указатели, а вторые структуры могут быть больше. Вы можете комбинировать их, чтобы получить switch способных перечислений на основе указателей - это оставлено как упражнение!

Обе эти конструкции также имеют (не) преимущество, заключающееся в том, что число перечисляемых "литералов" может быть увеличено в любое время.

2 голосов
/ 12 февраля 2012

Если вы просто хотите примитивный контейнер для типа и значения, рассмотрите следующий подход:

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

Опять же, иерархия классов может стоить учитывать, если вещи становятся сложными или лучше обрабатываются динамически. Предупреждение: если у вас есть тонна объектов для сохранения и / или создания, тип objc будет излишним и снизит производительность.

К сожалению, мой Java-Fu недостаточно хорош, чтобы знать все различия в lang для перечислений.

1 голос
/ 12 февраля 2012

На самом деле вы можете присвоить значения клавишам перечисления в 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"
0 голосов
/ 11 марта 2014

Ответы на основе структуры выглядят хорошо на первый взгляд, но терпят неудачу, когда вы пытаетесь добавить объекты Objective-C в структуру.Учитывая это ограничение, настоящая эмуляция перечисления в стиле Java может потребовать больше усилий, чем оно того стоит.

0 голосов
/ 16 апреля 2013

Я недавно использовал формат j2objc для перечислений.Это работает довольно хорошо.Кроме того, вы можете автоматически генерировать перечисления, если вы пытаетесь отобразить непосредственно из Java-объекта.

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

Однако я удалил определенные классы j2objc из своих «Перечислений».Я не хотел дополнительных зависимостей.

0 голосов
/ 12 февраля 2012

Это не 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];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...