Custom Enums - Unknown Type - objective-c

Moving on with my game a bit I want to add difficulties etc.
Coming to Objective-C from C#, I was hoping I could have some enums like this
typedef enum GameTypes{
Classic = 0,
Unlimited,
Timed,
Expert,
} GameType;
typedef enum GameDifficultys
{
Easy = 0,
Medium,
Hard,
} GameDifficulty;
and then have something like this:
GameType gameType = GameTypes.Classic;
GameDifficulty gameDifficulty = GameDifficultys.Easy;
However I get this following error:
Unknown type name "GameType"/"GameDifficulty"
Is this possible like it is in C#?
Thanks

C# is one of the worst things to ever happen to C.
Your question has nothing to do with Objective-C, it's a plain C question.
typedef enum GameTypes{
Classic = 0,
Unlimited,
Timed,
Expert,
} GameType;
That code does several things (of which I will only describe the easy ones). First, it declares an enumeration type, which can be used as enum GameTypes. For example:
enum GameTypes gameType = Classic;
Second, it puts those 4 names into the global namespace, such that Classic, Unlimited, Timed, and Expert can be used, and must not be duplicated as symbols.
Third, it creates a type alias called GameType which can be used as an alias for enum GameTypes.
So, for your specific example, you should not differentiate enum GameTypes and GameType. Instead, you should probably do something like this:
typedef enum GameType {
GameTypeClassic = 0,
GameTypeUnlimited,
GameTypeTimed,
GameTypeExpert,
} GameType;
typedef enum GameDifficulty
{
GameDifficultyEasy = 0,
GameDifficultyMedium,
GameDifficultyHard,
} GameDifficulty;
and then...
GameType gameType = GameTypeClassic;
GameDifficulty gameDifficulty = GameDifficultyEasy;
Also, you do not have to assign the first element as 0 because the first element of an enumeration will always get 0 unless it is explicitly overridden.

You seem to have defined the enums wrong. In C the following seems to be the convention:
typedef enum {
Classic = 0,
Unlimited,
Timed,
Expert,
} GameTypes;
typedef enum
{
Easy = 0,
Medium,
Hard,
} GameDifficulties;
Even so, I'd stick with Apple's naming conventions when using enums in Objective-C, which would result in something like:
typedef enum {
GameTypeClassic = 0,
GameTypeUnlimited,
GameTypeTimed,
GameTypeExpert,
} GameType;
typedef enum
{
GameDifficultyEasy = 0,
GameDifficultyMedium,
GameDifficultyHard,
} GameDifficulty;
Now you'll be able to assign values like this:
GameType gameType = GameTypeClassic;
GameDifficulty gameDifficulty = GameDifficultyEasy;
Check how enums are defined in UITableView.h for comparison: https://github.com/enormego/UIKit/blob/master/UITableView.h

Related

Objective-C enum in Swift

I have the following enum in an Objective-C file:
typedef NS_ENUM(NSInteger, countDirection){
countDirectionUp = 0,
countDirectionDown
};
How can I use this in a Swift view controller? I have tried this:
label.countDirection = countDirection.countDirectionDown
but I get an error:
countDirection.Type does not have a member named countDirectionDown
These get translated to
countDirection.Up
countDirection.Count
Swift removes as many letters as possible that the enum values have in common with the enumeration name. In your case, with an enumeration called countDirection and a value countDirectionUp, the whole "countDirection" is removed. It's not needed because you know which enum you are using, making your code considerable shorter.
With a bridging header and your enum values, I get the same error you do. However, if I change the enum values to:
typedef NS_ENUM(NSInteger, countDirection) {
cdUp = 0,
cdDown
};
...then I don't get any errors. For some reason, Swift does not like enum values that begin with the type name.
No error with these enum values either:
typedef NS_ENUM(NSInteger, countDirection) {
CountDirectioUp = 0,
CountDirectionDown
};

How do I convert this enum to an NS_ENUM?

I've been working on converting Objective-C code to use NS types so we can more easily switch between 32- and 64-bit. Most of the enums I've run into look like this:
typedef enum {
ValueA = 0,
ValueB,
...
ValueN,
} NameOfEnum;
and so I simply replace typedef enum with typedef NS_ENUM(NSInteger, NameOfEnum), remove the trailing NameOfEnum, and move on, making code that looks like this:
typedef NS_ENUM(NSInteger, NameOfEnum) {
ValueA = 0,
ValueB,
...
ValueN,
};
However, one special library formats its enums like such:
enum NameOfEnum
{
ValueA = 0,
ValueB,
...
ValueN,
};
typedef enum NameOfEnum NameOfEnum;
How do I convert this? Intuitively I want to replace enum NameOfEnum with my standard typedef NS_ENUM(NSInteger, NameOfEnum) and just delete that last line altogether. Is that the right thing to do, or will that possibly break something else far along in this extensive library?
You are correct. The last one first creates an enum and then creates a type with the same name.

Can an "enum" be used for flags in COM?

In the IDL for a COM object I do the following:
enum TxMyFlags
{
, flagOption = 1,
, flagOtherOption = 2,
, flagMoreOption = 4,
, flagAnotherFlag = 8,
, flagExtra = 128
// etc.
};
and have functions that can take the sum (or bitwise-OR, same thing) of flags, e.g. (in IDL)
HRESULT _stdcall a_method([in] enum TxMyFlags);
with an example of intended usage being:
a_method( flagExtra | flagMoreOption );
It seems to work but is this actually permitted, or is it possible that the RPC transport or whatever would reject values of an enum parameter that are not exactly in the enum definition?
If your client and server are in process (and there is no real mashaling happening, no RPC involved), you will not see any problem as the enum, however you define it, will be treated as its int/long/whatever integral type equivalent in size.
So it's the out-of-process (or cross apartment marshaling) case that maybe an issue. In this case, as stated in the doc here: enum attribute (and in your comments):
Objects of type enum are int types, and their size is
system-dependent. By default, objects of enum types are treated as
16-bit objects of type unsigned short when transmitted over a network.
Values outside the range 0 - 32,767 cause the run-time exception
RPC_X_ENUM_VALUE_OUT_OF_RANGE. To transmit objects as 32-bit entities,
apply the [v1_enum] attribute to the enum typedef.
So you basically have two options to use enums in idl: 1) use enum without typedef and 2) use enum with typedef and add the v1_enum attribute. In the first case, you can just declare the type in the method as you want on the wire, in the second, you will have to use that type (hence the v1_enum attribute):
enum MY_ENUM
{
MY_ENUM_FIRST = 1,
MY_ENUM_SECOND = 2,
};
typedef [v1_enum] enum
{
MY_ENUM_TYPE_FIRST = 1,
MY_ENUM_TYPE_SECOND = 2
} MY_ENUM_TYPE;
[object, uuid(15A7560E-901B-44D2-B841-58620B1A76C5)]
interface IMyInterface : IUnknown
{
HRESULT MyMethod1(int myParam);
HRESULT MyMethod2(MY_ENUM_TYPE myParam);
};
used like this:
IMyInterface *p = ...;
p->MyMethod1(MY_ENUM_FIRST | MY_ENUM_SECOND);
p->MyMethod2(MY_ENUM_TYPE::MY_ENUM_TYPE_FIRST | MY_ENUM_TYPE::MY_ENUM_TYPE_SECOND);
If you declare a method like this:
HRESULT MyMethod1(enum MY_ENUM myParam);
Then you will use a 16-bit enum (and you can't add v1_enum on a not-typedef'd enum), so that's not good (unless you're ok with the 0-32767 limit).
Note I also declared this to ease typedef enum as flags conversion in the second line:
MY_ENUM_TYPE operator | (MY_ENUM_TYPE l, MY_ENUM_TYPE r) { return (MY_ENUM_TYPE)((int)l | (int)r); }
Well. The typedef way seems a bit overkill to me, but it has the advantage of being typed. If you scan Microsof's own .IDL files in the Windows SDK, you'll see they basically use both...

unnamed enum & typedef?

I was getting a little confused with typedef/enum until I realised that I did not need to name the emun. Are there any differences / benefits between these two when used with typedef, the 2nd one to me seems a lot easier to understand.
First Example:
typedef enum enumMenuItems {
none,
add,
save,
load,
list,
remove
} menuItems;
menuItems optionSelect = none;
Second Example:
typedef enum {
Earth = 1,
Mars,
Saturn,
Neptune,
Jupiter
} planets;
planets closest = Mars;
.
EDIT:
typedef enum enumMenuItems {
none,
add,
save,
load,
list,
remove
} menuItems;
So the above essentially defines two types, one an enum called enumMenuItems and the second a typedef of enumMenuItems called menuItems.
menuItems optionSelect = save;
enum enumMenuItems optionSelect = save;
The above two declarations are essentially the same, one using the typedef and the other using the enum. So if your using a typedef you can leave your enum unnamed as the type can be accessed via the typedef menuItem.
gary
The first case allows you to refer to the type as enum enumMenuItems. For example:
enum enumMenuTimes optionSelect = none;
It might be clearer if you break it down into two parts:
enum _planets {
Earth = 1,
Mars,
Saturn,
Neptune,
Jupiter
};
typedef enum _planets planets;
enum _planets planet1 = Earth;
planets planet2 = Mars;
If that simplifies the concept for you. Your second notation there is just shorthand; it creates an anonymous enumeration and then uses typedef to give it a name. You could even, for example, do:
enum {
Value0,
Value1,
Value2
};
But you'd not be able to use the enumeration as a fake type name, like you're trying to do. You can still access the enumerated values, though.
A more in depth description is available at the comp.lang.c FAQ.

What is a typedef enum in Objective-C?

I don't think I fundamentally understand what an enum is, and when to use it.
For example:
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
What is really being declared here?
Three things are being declared here: an anonymous enumerated type is declared, ShapeType is being declared a typedef for that anonymous enumeration, and the three names kCircle, kRectangle, and kOblateSpheroid are being declared as integral constants.
Let's break that down. In the simplest case, an enumeration can be declared as
enum tagname { ... };
This declares an enumeration with the tag tagname. In C and Objective-C (but not C++), any references to this must be preceded with the enum keyword. For example:
enum tagname x; // declare x of type 'enum tagname'
tagname x; // ERROR in C/Objective-C, OK in C++
In order to avoid having to use the enum keyword everywhere, a typedef can be created:
enum tagname { ... };
typedef enum tagname tagname; // declare 'tagname' as a typedef for 'enum tagname'
This can be simplified into one line:
typedef enum tagname { ... } tagname; // declare both 'enum tagname' and 'tagname'
And finally, if we don't need to be able to use enum tagname with the enum keyword, we can make the enum anonymous and only declare it with the typedef name:
typedef enum { ... } tagname;
Now, in this case, we're declaring ShapeType to be a typedef'ed name of an anonymous enumeration. ShapeType is really just an integral type, and should only be used to declare variables which hold one of the values listed in the declaration (that is, one of kCircle, kRectangle, and kOblateSpheroid). You can assign a ShapeType variable another value by casting, though, so you have to be careful when reading enum values.
Finally, kCircle, kRectangle, and kOblateSpheroid are declared as integral constants in the global namespace. Since no specific values were specified, they get assigned to consecutive integers starting with 0, so kCircle is 0, kRectangle is 1, and kOblateSpheroid is 2.
Apple recommends defining enums like this since Xcode 4.4:
typedef enum ShapeType : NSUInteger {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
They also provide a handy macro NS_ENUM:
typedef NS_ENUM(NSUInteger, ShapeType) {
kCircle,
kRectangle,
kOblateSpheroid
};
These definitions provide stronger type checking and better code completion. I could not find official documentation of NS_ENUM, but you can watch the "Modern Objective-C" video from WWDC 2012 session here.
UPDATE
Link to official documentation here.
An enum declares a set of ordered values - the typedef just adds a handy name to this. The 1st element is 0 etc.
typedef enum {
Monday=1,
...
} WORKDAYS;
WORKDAYS today = Monday;
The above is just an enumeration of shapeType tags.
A user defined type that has the possible values of kCircle, kRectangle, or kOblateSpheroid. The values inside the enum (kCircle, etc) are visible outside the enum, though. It's important to keep that in mind (int i = kCircle; is valid, for example).
Update for 64-bit Change:
According to apple docs about 64-bit changes,
Enumerations Are Also Typed : In the LLVM compiler, enumerated types can
define the size of the enumeration. This means that some enumerated
types may also have a size that is larger than you expect. The
solution, as in all the other cases, is to make no assumptions about a
data type’s size. Instead, assign any enumerated values to a variable
with the proper data type
So you have to create enum with type as below syntax if you support for 64-bit.
typedef NS_ENUM(NSUInteger, ShapeType) {
kCircle,
kRectangle,
kOblateSpheroid
};
or
typedef enum ShapeType : NSUInteger {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Otherwise, it will lead to warning as Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType
Update for swift-programming:
In swift, there's an syntax change.
enum ControlButtonID: NSUInteger {
case kCircle , kRectangle, kOblateSpheroid
}
The enum (abbreviation of enumeration) is used to enumerate a set of values (enumerators). A value is an abstract thing represented by a symbol (a word).
For example, a basic enum could be
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl };
This enum is called anonymous because you do not have a symbol to name it. But it is still perfectly correct. Just use it like this
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
Ok. The life is beautiful and everything goes well. But one day you need to reuse this enum to define a new variable to store myGrandFatherPantSize, then you write:
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandFatherPantSize;
But then you have a compiler error "redefinition of enumerator". Actually, the problem is that the compiler is not sure that you first enum and you are second describe the same thing.
Then if you want to reuse the same set of enumerators (here xs...xxxxl) in several places you must tag it with a unique name. The second time you use this set you just have to use the tag. But don't forget that this tag does not replace the enum word but just the set of enumerators. Then take care to use enum as usual. Like this:
// Here the first use of my enum
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
// here the second use of my enum. It works now!
enum sizes myGrandFatherPantSize;
you can use it in a parameter definition as well:
// Observe that here, I still use the enum
- (void) buyANewDressToMyGrandMother:(enum sizes)theSize;
You could say that rewriting enum everywhere is not convenient and makes the code looks a bit strange. You are right. A real type would be better.
This is the final step of our great progression to the summit. By just adding a typedef let's transform our enum in a real type. Oh the last thing, typedef is not allowed within your class. Then define your type just above. Do it like this:
// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type
#interface myClass {
...
size_type myGrandMotherDressSize, myGrandFatherPantSize;
...
}
Remember that the tag is optional. Then since here, in that case, we do not tag the enumerators but just to define a new type. Then we don't really need it anymore.
// enum definition
typedef enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } size_type;
#interface myClass : NSObject {
...
size_type myGrandMotherDressSize, myGrandFatherPantSize;
...
}
#end
If you are developing in Objective-C with XCode I let you discover some nice macros prefixed with NS_ENUM. That should help you to define good enums easily and moreover will help the static analyzer to do some interesting checks for you before to compile.
Good Enum!
typedef is useful for redefining the name of an existing variable type. It provides short & meaningful way to call a datatype.
e.g:
typedef unsigned long int TWOWORDS;
here, the type unsigned long int is redefined to be of the type TWOWORDS. Thus, we can now declare variables of type unsigned long int by writing,
TWOWORDS var1, var2;
instead of
unsigned long int var1, var2;
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
then you can use it like :-
ShapeType shape;
and
enum {
kCircle,
kRectangle,
kOblateSpheroid
}
ShapeType;
now you can use it like:-
enum ShapeType shape;
enum is used to assign value to enum elements which cannot be done in struct. So everytime instead of accessing the complete variable we can do it by the value we assign to the variables in enum. By default it starts with 0 assignment but we can assign it any value and the next variable in enum will be assigned a value the previous value +1.
You can use in the below format, Raw default value starting from 0, so
kCircle is 0,
kRectangle is 1,
kOblateSpheroid is 2.
You can assign your own specific start value.
typedef enum : NSUInteger {
kCircle, // for your value; kCircle = 5, ...
kRectangle,
kOblateSpheroid
} ShapeType;
ShapeType circleShape = kCircle;
NSLog(#"%lu", (unsigned long) circleShape); // prints: 0
A typedef allows the programmer to define one Objective-C type as another. For example,
typedef int Counter; defines the type Counter to be equivalent to the int type. This drastically improves code readability.
The Typedef is a Keyword in C and C++. It is used to create new names for basic data types (char, int, float, double, struct & enum).
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
Here it creates enumerated data type ShapeType & we can write new names for enum type ShapeType as given below
ShapeType shape1;
ShapeType shape2;
ShapeType shape3;
enum can reduce many types of "errors" and make the code more manageable
#define STATE_GOOD 0
#define STATE_BAD 1
#define STATE_OTHER 2
int STATE = STATE_OTHER
The definition has no constraints. It's simply just a substitution.
It is not able to limit all conditions of the state. When the STATE is assigned to 5, the program will be wrong, because there is no matching state. But the compiler is not going to warn STATE = 5
So it is better to use like this
typedef enum SampleState {
SampleStateGood = 0,
SampleStateBad,
SampleStateOther
} SampleState;
SampleState state = SampleStateGood;