How to add enum as datasource in uipickerview? - objective-c

I have created one enum in my ApplicationConstants.h file and enum is as below.
typedef enum {
CurrentLocation = 0,
CurrentCity,
CurrentRegion } enumLocation;
Now the question is I dont know how to set this enum as data source in UIPickerView ! Can anyone give me idea about this ? I have used NSArray as datasource before. But I want enum now. Because of this problem I stuck. Can you help me ? So i can go ahead in my application.

You can't display the identifier of an enum directly. You have to prepare a big if/else/switch block to prepare a string for each element, or add strings for every element in an array and select by index from there.
Enum types are usually used instead of magic numbers in programs and thus are designed to make the code easier to read by a human, but the underlying representation is in one of the base data types (int, char, etc).

For UIPickerViewDataSource
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return LOCATION_COUNT;
}
Use the trick for enum count
typedef enum { CurrentLocation = 0, CurrentCity, CurrentRegion, LOCATION_COUNT} enumLocation;
for UIPickerViewDelegate
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
[self.enumLocationStringDict objectForKey:[NSNumber numberWithInt:row]]
}
Dictionary can be as follow
self.enumLocationStringDict = [NSDictionary dictionaryWithObjectsAndKeys:
#"CurrentLocation", [NSNumber numberWithInt:CurrentLocation],
#"CurrentCity", [NSNumber numberWithInt:CurrentCity],
#"CurrentRegion", [NSNumber numberWithInt:CurrentRegion],
,nil];

you can choose the way to define a simple macro for it for instace, like this:
in the header file (.h):
#define NAMEOF(var) ##var
typedef enum : NSInteger {
CustomTypeUknown = 0,
CustomTypeSomething,
CustomTypeParticularValue,
CustomTypeBoringValue,
} CustomType;
in the implementaion file (.m)
NSArray *_array = [NSArray arrayWithObjects:NAMEOF(CustomTypeUknown), NAMEOF(CustomTypeSomething), NAMEOF(CustomTypeParticularValue), NAMEOF(CustomTypeBoringValue), nil];
the objects will be strings with the names, but for safety sake you could check the values via logging _array:
NSLog(#"%#", _array);
it should look like this:
(
CustomTypeUknown,
CustomTypeSomething,
CustomTypeParticularValue,
CustomTypeBoringValue
)
if I haven't misunderstood your problem, that is you looked for...

Related

How to check a typedef'd obj in Objective-c NSDictionary

I've got an method that takes NSDictionary arg. This NSDictionary has some predefined keys it'll take. All the obj's should be strings. But only certain string objs are valid for each key.
So my approach was to typedef NSString for each valid string per key. I'm hoping not to extend the NSString class.
I've typedef'd some NSString's...
typedef NSString MyStringType
Then I define a few...
MyStringType * const ValidString = #"aValidString";
Here's what I'd like to do in my sample method..
- (void)setAttrbiutes:(NSDictionary *)attributes {
NSArray *keys = [attributes allKeys];
for (NSString *key in keys) {
if ([key isEqualToString:#"ValidKey"]) {
id obj = [attributes objectForKey:key];
//Here's where I'd like to check..
if (**obj is MyStringType**) {
}
}
}
}
I'm open to other ideas if there's a better approach to solve the obj type problem of an NSDictionary.
Doesn't work like that; typedefs are a compile time alias that don't survive being passed through a dictionary.
In any case, using typedefs for something like this would be unwieldy.
I suggest you create a property list -- either as a file in your project or in code -- that contains the specifications of your various keys and valid values, then write a little validator that, passed a string and value, can validate the string-value pair for validity.
This also gives you the flexibility to extend your validator in the future. For example, you might have a #"Duration" key that can only be in the range of 1 to 20.
Instead of setting up a typedef for you special values, one possible option would be to create an NSSet of the special values. Then in your code you can verify that the object in the dictionary is in your set.
What about a combination of category on NSString + associated object?
Something along the lines (untested!!):
#interface NSString (BBumSpecial)
- (NSString *) setSpecial: (BOOL) special ;
- (BOOL) special ;
#end
and:
#implementation NSString (BBumSpecial)
static void * key ;
- (NSString *) setSpecial: (BOOL) special {
objc_setAssociatedObject(self, &key, special ? #YES : #NO, OBJC_ASSOCIATION_ASSIGN) ;
return self ;
}
- (BOOL) special {
id obj = objc_getAssociatedObject(self, &key) ;
return obj && [obj boolValue] ;
}
#end
Which you could then use as:
NSString * mySpecialString = [#"I'm Special" setSpecial:YES] ;
?

Increment NSNumber in NSArray

I've seen this, but there needs to be an easier way than that.
If I have an array of NSNumbers and I want to increment one of them, I have to do this?
[myMutableArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInt:[(NSNumber *)[myMutableArray objectAtIndex:index] intValue] + 1]];
or
myArray = [myArray.mutableCopy replaceObjectAtIndex:index withObject:[NSNumber numberWithInt:[(NSNumber *)[myArray objectAtIndex:index] intValue] + 1]].copy;
if you decide to use an immutable array for some reason.
I know I could always just use an int array, but I was just curious if there was a simple way to do this.
Also, how should I define an int array if I need access to it either within an implementation or a full file (the entire .m) without making it global?
Would it just be as simple as throwing this at the top of my implementation / file?
static int *myInt;
As others said, yes, you need that many steps. With literals, it can be a little easier to read:
myMutableArray[index] = #( [ myMutableArray[index] intValue] + 1 ) ;
Your second code example won't work because replaceObjectAtIndex:withObject: returns void, not the NSMutableArray it acted upon. You'd need to create a mutableCopy of the NSArray, then replaceObject, then set the NSArray to a copy of the NSMutableArray.
I would recommend using C++ STL containers rather than creating a plain int array if you need to be able to resize it. Rename your implementation file's extension to .mm instead of .m.
std::vector<int> numbers = { 2, 4, 6 };
numbers[1]++; // { 2, 5, 6 }
Remember to include the container's definition.
#import <vector>

set ivars from NSDictionnary

I'm currently working on a project where the user defines some parameters in a NSDictionnary, that I'm using to setup some objects.
For example, you can ask to create a Sound object with parameters param1=xxx, param2=yyy, gain=3.5 ... Then an Enemi object with parameters speed=10, active=YES, name=zzz ...
{
active = NO;
looping = YES;
soundList = "FINAL_PSS_imoverhere_all";
speed = 100.0;
}
I then instantiate my classes, and would like to set the ivars automatically from this dictionnary.
I've actually wrote some code to check that this parameter exists, but I'm having trouble in actually setting the parameter value, especially when the parameter is non object (float or bool).
Here's what I'm doing so far :
//aKey is the name of the ivar
for (NSString *aKey in [properties allKeys]){
//create the name of the setter function from the key (parameter -> setParameter)
NSString *setterName = [aKey stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[aKey substringToIndex:1] uppercaseString]];
setterName = [NSString stringWithFormat:#"set%#:",setterName];
SEL setterSelector = NSSelectorFromString(setterName);
//Check if the parameter exists
if ([pge_object respondsToSelector:setterSelector]){
//TODO : automatically set the parameter
}
else{
[[PSMessagesChecker sharedInstance]logMessage:[NSString stringWithFormat:#"Cannot find %# on %#", aKey, [dict objectForKey:#"type"]] inColor:#"red"];
NSLog(#"Cannot find %# on %#", aKey, [dict objectForKey:#"type"]);
}
}
}
As you can see, I don't know what to do once I've found that the parameter exists on the object. I tried to use "performSelector... withObject..., but my problem is that some of the parameters are non-objects (float or bool).
I also tried to get the class of the parameter, by using the setter, but it didn't help.
Did anyone manage to do something like that?
Jack Lawrence's comment is spot on.
What you are looking for is called Key Value Coding, or just KVC.
This fundamental part of Cocoa lets you get and set any instance variable using its name as a String and a new value.
It will automatically handle coercing Objects to primitive values, so you can use it for int and float properties too.
There is also support for validating values and handling unknown properties.
see the docs
your code, without validation, could be written
for( id eachKey in props ) {
[anOb setValue:props[eachKey] forKey:eachKey];
}
or just
[anOb setValuesForKeysWithDictionary:props];
as Jack said.
For the non-object parameters you have to put them into an object, for example NSNumber or NSValue. You can then add these objects into your dictionary.
For Example:
float f = 0.5;
NSNumber f_obj = [NSNumber numberWithFloat:f];

Is there a concise way to map a string to an enum in Objective-C?

I have a string I want to parse and return an equivalent enum. I need to use the enum type elsewhere, and I think I like how I'm defining it. The problem is that I don't know a good way to check the string against the enum values without being redundant about the order of the enums.
Is there no option other than a big if/else?
typedef enum {
ZZColorRed,
ZZColorGreen,
ZZColorBlue,
} ZZColorType;
- (ZZColorType)parseColor:(NSString *)inputString {
// inputString will be #"red", #"green", or #"blue" (trust me)
// how can I turn that into ZZColorRed, etc. without
// redefining their order like this?
NSArray *colors = [NSArray arrayWithObjects:#"red", #"green", #"blue", nil];
return [colors indexOfObject:inputString];
}
In Python, I'd probably do something like the following, although to be honest I'm not in love with that either.
## maps url text -> constant string
RED_CONSTANT = 1
BLUE_CONSTANT = 2
GREEN_CONSTANT = 3
TYPES = {
'red': RED_CONSTANT,
'green': GREEN_CONSTANT,
'blue': BLUE_CONSTANT,
}
def parseColor(inputString):
return TYPES.get(inputString)
ps. I know there are color constants in Cocoa, this is just an example.
try this: Map enum to char array
Pseudo code.. untested.
int lookup(const char* str) {
for(name = one; name < NUMBER_OF_INPUTS; name++) {
if(strcmp(str, stats[name]) == 0) return name;
}
return -1;
}
A more objective-c'ish version of the code could be:
// build dictionary
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
for(i=0; i<number_of_strings; i++) {
[dict setObject:[NSNumber numberWithInteger:i] forKey:[NSString stringWithUTF8String:names[i]]];
}
// elsewhere... lookup in dictionary
id obj = [dict objectForKey:name];
if(obj) return [obj intValue];
return -1;
This has already been answered: Converting between C enum and XML
Basically, you wind up defining corresponding strings when you define your enum, and then you use a category on NSArray so that you can do this:
static NSArray* colorNamesArray = [[NSArray alloc] initWithObjects:colorNames];
//colorNames is a nil-terminated list of string literals #defined near your enum
NSString* colorName = [colorNamesArray stringWithEnum:color];
//stringWithEnum: is defined with a category
Sure, the #define is a little ugly, but the code above, which is what you'll work with most of the time, is actually pretty clean.
I was never satisfied with any of the suggestions. (But I appreciate the effort that went into them.) I tried a few of them but they didn't feel good or were error-prone in practice.
I ended up created a custom dictionary to map integers to strings which feels a lot better because it's Cocoa through and through. (I didn't subclass NSDictionary in order to make it harder to misuse.)
#interface ZZEnumDictionary : NSObject {
NSMutableDictionary *dictionary;
}
+ (id)dictionary;
+ (id)dictionaryWithStrings:(id)firstString, ...;
- (NSString *)stringForInt:(NSInteger)intEnum;
- (NSInteger)intForString:(NSString *)stringEnum;
- (BOOL)isValidInt:(NSInteger)intEnum;
- (BOOL)isValidString:(NSString *)stringEnum;
- (BOOL)stringEquals:(NSString *)stringEnum intEnum:(NSInteger)intEnum;
- (BOOL)setContainsString:(NSSet *)set forInt:(NSInteger)intEnum;
- (NSArray *)allStrings;
#end
#interface ZZEnumDictionary ()
- (void)setInt:(NSInteger)integer forString:(NSString *)string;
#end

Accessing constants using Key-Value Coding in Objective-C

I'm making a program that has a lot of constants. I decided to put them all into a separate class and I'm importing it by the classes that need it. The files look similar to this
// Constants.h
extern const int baseCostForBuilding;
extern const int maxCostForBuilding;
// etc
// Constants.m
const int baseCostForBuilding = 400;
const int maxCostForBuilding = 1000;
// etc
What I'm trying to do is access them using key-value coding. What I've tried so far hasn't worked.
id object = [self valueForKey:#"baseCostForBuilding"];
But I can do the following and it works fine.
id object = baseCostForBuilding;
This may seem pointless but I have a lot of variables that have to end in "CostForBuilding" and the function I need this in only gets the first part of the string. Example, "base", "max", "intermediate", etc. It will then combine it with "CostForBuilding" or something else to get the variable name.
If this is possible, it would be way nicer to only have one or two lines of code instead of multiple if-statements to access the correct variable. Does anyone know a way to do this? Thanks in advance.
You can fill a dictionary with the appropriate values:
- (id)init
{
...
buildingCosts = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithInt:100], #"base",
[NSNumber numberWithInt:200], #"max",
...,
nil];
...
}
- (int)buildingCostForKey:(NSString *)key
{
return [(NSNumber *)[buildingCosts objectForKey:key] intValue];
}
- (void)dealloc
{
[buildingCosts release];
}
Which you could then use as follows:
int baseCost = [myClass buildingCostForKey:#"base"];