How to get enum value by name in Objective-C - objective-c

typedef NS_ENUM(NSInteger, CameraMode) {
DEFAULT,
SMART,
LIVENESS,
DOCUMENT
};
I want to to something like
NSInt *mode = CameraMode.getValue("DEFAULT");
is it possible with Objective-C? I did something similar in Java like this:
CameraMode.valueOf("DEFAULT");

Objective-C doesn't support any extra functionality as part of enums, however nothing prevents you from writing your own helper functions:
typedef NS_ENUM(NSUInteger, TDWState) {
TDWStateDefault,
TDWStateSmart,
TDWStateLiveness,
TDWStateUndefined
};
TDWState TDWStateFromString(NSString *string) {
static const NSDictionary *states = #{
#"DEFAULT": #(TDWStateDefault),
#"SMART": #(TDWStateSmart),
#"LIVENESS": #(TDWStateLiveness),
};
NSNumber *state = [states objectForKey:string];
if (state) {
return state.unsignedIntValue;
} else {
return TDWStateUndefined;
}
};
Which then can be used like this:
TDWState state = TDWStateFromString(#"DEFAULT");

There is no language-support for something like this. After all, typedef NS_ENUM(NSInteger, CameraMode) { … } is basically just C with some fancy macros.
You have to implement such string to enum mappings yourself, unfortunately.

Related

Fails to write proper syntax for block that uses typedef

I have Objective-C code that I try to convert to Swift but failed.
typedef void (^ CDVAddressBookWorkerBlock)(
ABAddressBookRef addressBook,
CDVAddressBookAccessError* error
);
#interface CDVAddressBookHelper : NSObject
{}
- (void)createAddressBook:(CDVAddressBookWorkerBlock)workerBlock;
#end
And this is Objective-C implementation:
CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
[abHelper createAddressBook:
^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode)
{
/* ...*/
}
];
How to write it in Swift?
From documentation:
{(parameters) -> (return type) in expression statements}
This is a template xCode offers:
This is what I tried:
var abHelper:CDVAddressBookHelper = CDVAddressBookHelper()
abHelper.createAddressBook(
{(addrBook:ABAddressBookRef, errCode:CDVAddressBookAccessError) in
if addrBook == nil {
}
} )
Error:
Type 'ABAddressBook!' does not conform to protocol 'AnyObject'`
[EDIT]
Regards to: swift-closure-declaration-as-like-block-declaration post I tried to write typealias:
typealias CDVAddressBookWorkerBlock = (addrBook:ABAddressBookRef, errCode:CDVAddressBookAccessError) -> ()
What next?
How to make it work?
Thanks,
Check out the docs about how to work with Cocoa and Core Foundation.
This should work:
abHelper.createAddressBook() {
(addrBook:ABAddressBook?, errCode:CDVAddressBookAccessError!) in
if addrBook == nil {
}
}

New Test Fixture for each iteration over enum members

My tests are contained within functions declared with TEST_F so that I can use a new test fixture object between tests. For each TEST_F, a new instance of the test fixture is created. But what if I wish to loop over an enum in my test and have a new instance of the test fixture for each iteration? What should I do in this case?
It sounds like you want to use value-parameterized tests.
You could iterate through the values of an enum like this:
#include <iostream>
#include "gtest/gtest.h"
enum Malt { bowmore = 10, talisker, scapa };
class Whisky {
public:
explicit Whisky(const Malt& malt) : malt_(malt) {}
bool IsIslay() const { return malt_ == bowmore; }
private:
Malt malt_;
};
class DramTest : public testing::TestWithParam<Malt> {
protected:
DramTest() : whisky_(GetParam()) {}
Whisky whisky_;
};
TEST_P(DramTest, IsIslay) {
if (GetParam() == bowmore)
EXPECT_TRUE(whisky_.IsIslay());
else
EXPECT_FALSE(whisky_.IsIslay());
}
INSTANTIATE_TEST_CASE_P(AllMalts, DramTest,
testing::Values(bowmore, talisker, scapa));
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
If you have a large number of enum values, you could use the Range generator instead of the Value one:
testing::Range<int>(bowmore, scapa + 1)
but this needs some casting in the fixture between ints and the enum type.
Both options suffer from maintenance problems; if you add a new enum value, you need to remember to change the test.

Obj-C function declaration needs semi-colon?

This is really simple but driving me nuts.
I am trying to implement a simple function in my Objective-C code. When I write this,
NSInteger Sort_Function(id id1, id id2, void *context) {
}
I get an error that a semi-colon was expected at the end of the declaration. However, I've seen this type of syntax in many, many examples. What could I possibly be doing wrong? If it matters, this is an iOS app and the function is nested in an if clause. Thanks in advance.
The function definition -- this snippet you posted -- is "nested in a if clause"? That's unfortunately illegal in C (and Obj-C by extension) -- all function declarations and definitions have to be at the top level of the file. Inside an #implementation section is also an option:
// Start of file
// Declaration or definition valid here
void my_func(void); // Declaration
void my_other_func(void);
void my_third_func(void);
void my_func(void) { // Definition
return;
}
#implementation MyClass
// Definition also valid here
void my_other_func(void) {
return;
}
- (void) myMethod {
if( YES ){
void my_third_func(void) { // Invalid here
return;
}
}
}
#end
Is it possible you're confusing the function syntax with block syntax?
// The caret indicates definition of a block, sort of an anonymous function
int (^myBlock)(int);
myBlock = ^int (int my_int) {
return my_int;
};

Is this a good way to have class level member variables?

I'm trying to violate the laws of objective C a little by having static (class level) variables that have setters and getters:
+(CGRect*)defaultOpFr:(CGRect*)set{
static CGRect * defaultOpFr = nil;
if (set) {
if (!defaultOpFr) {
defaultOpFr = malloc(sizeof(defaultOpFr));
}
defaultOpFr->size.width = set->size.width;
defaultOpFr->size.height = set->size.height;
defaultOpFr->origin.x = set->origin.x;
defaultOpFr->origin.y = set->origin.y;
}
return defaultOpFr;
}
It seems to work, but I'm wondering if there's a better way. The idea is to call it with nil to retrieve the value, call it with a CGRect to set a new value.
Yup; that'll work, but be completely against any kind of common pattern.
Why don't you simply have a standard setter/getter pair? Even at the class level, that is fine:
static CGRect barf;
+ (CGRect) barf { return barf; }
+ (void) setBarf:(CGRect)aRect { barf = aRect; }
Done.

simulate java enum objective-c

in java an enum can be declared like this
enum MyEnum {
ONE("descr for one"),
TWO("descr for two");
private String descr;
MyEnum(String descr) {
this.descr=descr;
}
public String getDescr() {return this.descr;}
}
therefore we can always call myEnumInstance.getDescr() for getting enum description. It is possible of course to add several variable in constructor and create its corresponding accessor.
Is there anything similiar in objective-c ?
thanks
No. Unfortunately for you, there is nothing similar in ObjectiveC.
You can have a Helper Class mapping enums to NSString* though...
Something like this:
typedef enum {
kONE,
kTWO
} MyEnum;
And then a class method/message somewhere:
+ (NSString*) getDescriptionFor:(MyEnum)e
{
switch(e) {
case kONE:
return #"descr for one";
case kTWO:
return #"descr for two";
default:
break;
}
return #"";
}