I've created a typedef enum for my iPhone app...
typedef enum {
FirstType,
SecondType,
ThirdType
} type;
Just for testing I'd like to be able to pick a random type from these.
I was going to use arc4random() % 4 to do it and just use the int in its place but wanted to check if there was a better way of doing this.
typedef enum {
FirstType = 0,
SecondType,
ThirdType,
EnumTypeMax
} EnumType;
EnumType randomType = (EnumType) (arc4random() % (int) EnumTypeMax);
Note that EnumTypeMax is equal to 3, not 4 and that is correct.
EnumTypeMax is considered to be an invalid value.
Also, see my answer here about an X-Macros solution.
Related
I recently asked a question around sort of generic enum/structs in C and realized that although I brought up a comparison with the enum possibilities in e.g. Swift and Rust, I don't really understand how those are handled internally to those languages.
For Rust, I found a (rather roundabout) article titled Peeking inside a Rust enum
— look for the "But Rust enums aren't just that." heading and then keep scrolling until the "In Rust, it's called a discriminant." part. Eventually that part gets around to basically saying that Rust enums are sort of equivalent to something like this in C:
struct {
enum actual_options discriminant;
union {
/* … various data types/sub-structs corresponding to each option's need… */
};
};
Is it basically the same with a Swift enum under the hood? I.e. that I should expect an enum to have basically the same memory overhead as a struct of the largest possible option in my enum, plus at least one extra byte to store the tag/discriminant of the overarching case?
I'm also interested in what code gets generated to use whatever sort of underlying structure. I'm assuming it can't really much more fancy/optimized than what you'd do in C for the structure shown above? E.g.
struct raw_enum {
enum { case1, case2, case3 } tag;
union {
struct { int x; int y; } case1_data;
const char* case2_data;
struct { float a; double b; void* c; char d; } case3_data;
};
};
struct raw_enum d;
fill_in_some_value(&d);
if (d.tag == case1) {
// use `d.case1_data`…
} else if (d.tag == case2) {
// use `d.case2_data`…
} else if (d.tag == case3) {
// use `d.case3_data`…
} else {
// any runtime assertion for an unknown tag that could somehow sneak in???
}
Is that a reasonable approximation to what Swift does in the code it generates around enums?
MusicPlayer's API relies on variable length arrays as the last member of a struct to handle passing around data of unknown size. Looking at the generated interface for MusicPlayer, the structs used in this method present their last element in a single value tuple.
example:
struct MusicEventUserData {
var length: UInt32
var data: (UInt8)
}
I doubt that any of this has been officially exposed but has anyone figured out whether this syntax is a red herring or actually significant? I don't think that there is a means to hand arbitrarily sized things via swift but does this help when calling from C?
after test on a playground I can see there is no difference between (Int) and Int type.
Here is my tests :
func testMethod(param1: Int, param2: (Int)) -> Int{
return param1 + param2
}
testMethod(2, 3) // return 5
testMethod(3, (6)) // return 9
About the calling in C, I just think it is a little bug on the bridging from ObjC to swift
MusicPlayer is no longer exported as above. As of Xcode 6.3b1
typedef struct MusicEventUserData
{
UInt32 length;
UInt8 data[1];
} MusicEventUserData;
This is much closer to the C declaration. It still does not completely explain how to deal with the API in swift but that is another question.
I am attempting to do this in Swift:
var netStatus:NetworkStatus = reachability.currentReachabilityStatus();
if (!netStatus) { // error here says network status not convertible to bool
....
}
typedef enum : NSInteger {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} NetworkStatus;
I've also tried
if (netStatus ==0)
if (netStatus == NetworkStatus.NotReachable) // NetworkStatus.type does not have a member named 'NotReachable'
etc.
Try using modern objective-c practices:
typedef NS_ENUM(NSInteger, NetworkStatus) {
NetworkStatusNotReachable,
NetworkStatusReachableViaWiFi,
NetworkStatusReachableViaWAN
};
Adopting Modern Objective-C
Read the Swift manual on how to define enum. it's more like
enum NetworkStatus:Int {
case NotReachable = 0
case Reach....
}
Unfortunately an enum is not transferrable to Swift from Objective-C, it needs to be an NS_ENUM.
If you can change the definition of the enum, then Daniel T.'s solution is best.
However, if you cannot change the enum definition, then you can create an intermediary class to provide an NS_ENUM and a mapping to the enum values.
See: https://stackoverflow.com/a/24950414/600753 for more details.
I got a beginner question and I've surfed through the Internet and only find definition like
typedef enum
{
A,B,C,D
}CAP;
CAP a=A; // printf("%d",a); => 1
But my question is (from Stanford CS107 section handout ) that :
typedef enum {
Integer, String, List, Nil
} nodeType;
// skip
char *ConcatAll(nodeType *list)
{
switch (*list) {
case Integer:
case Nil: return strdup("");
case String: return strdup((char *)(list + 1));
}
nodeType **lists = (nodeType **)(list + 1);
// skip after
}
Since the nodeType is numeric (1 , 2, 3), how come it could be used as type declaration
nodeType *list;
and even this?
nodeType **lists = (nodeType **)(list + 1);
Or maybe there's a manual so I can find? Thank you for your kind advice!
When you define a type with typedef, you can use it wherever a type can be used. It's treated as if you'd used the type that was defined. So:
nodeType *list;
is equivalent to:
enum {Integer, String, List, Nil} *list;
I have predefined enum for buttons IDs:
typedef enum
{
button1ID = 407,
button2ID = 999,
button3ID = 408,
button4ID = 409,
} TOP_MENU_BUTTON_TYPE;
I need to find out if the ID I recieve is defiened in the enum. How can I do that? Something like:
if(id in TOP_MENU_BUTTON_TYPE)
There is no way to dynamically iterate an enum. Enums are static feature, they don't exist during runtime. In runtime they are just plain integers (of some size) and values.
It's not possible with this requirement you stated in bounty:
In your answer do not use hard coded values of the enum, just its type.
The other answers show you pretty much all ways to do it statically.
If I understand your question clearly, then this would be helpful to you..
Instead of using enum alone, you should try that with struct and here it is an answer by #Richard will help you how to do that.
Change enum values at runtime?
https://stackoverflow.com/a/10305425/1083859
In the above link, he explains how to use a dynamic enum values with struct and also you can iterate the values to find out. I think you will get an idea.
You can simply do this:
int validValue = button1ID | button2ID | button3ID | button4ID;
if (validValue & id)
// Valid enum value
An enum is not an object, it's just an integer that the compiler understands at build time. Because of this, you would need to provide low level code to make your check.
If you aren't pre-defining the values of your enums, they will start at 0 and increase by one. This lets you compare a value to see if it's <= your last element.
try this method:
-(BOOL)isDefined:(TOP_MENU_BUTTON_TYPE)type{
BOOL isDefined;
switch (type) {
case button1ID:
case button2ID:
case button3ID:
case button4ID:
isDefined = TRUE;
break;
default:
isDefined = FALSE;
break;
}
return isDefined;
}
//(...)
TOP_MENU_BUTTON_TYPE test;
test = 407;
NSLog(#"is %d a TOP_MENU_BUTTON_TYPE? result: %d", test, [self isDefined:test]);
test = 2;
NSLog(#"is %d a TOP_MENU_BUTTON_TYPE? result: %d", test, [self isDefined:test]);
so:
if ([self isDefined:test]){
// OK, test is defined in TOP_MENU_BUTTON_TYPE
}
in .h
typedef enum
{
407,
999,
408,
409,
} TOP_MENU_BUTTON_TYPE;
#interface CheckoutController : UIViewController{
TOP_MENU_BUTTON_TYPE type;
}
In .m
switch (status) {
case 407:
//Your Task
break;
case 999:
//Your Task
break;
case 408:
//Your Task
break;
case 409:
//Your Task
break;
}
Answers about using switch or bunch of || in if are correct, but…
If you have big enums (enum with a lot of values) you can make this simplier. Also Cocoa uses this trick.
Your enum values must be incremented by one.
Then add to enum two additional values:
typedef enum {
buttonIDMin = 407, // Lowest value
button1ID = 407,
button2ID = 408, // Incremented by ONE
button3ID = 409,
button4ID = 410,
buttonIDMax = 410, // Highest value
} TOP_MENU_BUTTON_TYPE;
When you are comparing, you just need to do:
if (buttonID >= buttonIDMin && buttonID <= buttonIDMax) ...