can I switch NSString - ios

I want to switch NSString in XmlParser because if there are 15 or more web-service then every time the loop check for correct element in IF..ELSE.That I don't want to make processor busy..
I have searched a lot and found using enum I can switch NSString but no luck ..
I have tried each possibilities,but some where i am making mistake.
Please help to solve this big problem for me.
Here I have declare my enum:
Here in "elementName" I am getting Exact value as declared in enum:
But instead of 1, I am getting wrong value Like 202896536:

You cant do it by creating enum. You must need to compare the string.
if([elementName isEqualToString:#"UserLoginComplexType"])
//Do something...

You can not cast a string to ENUM value, you will need to parse it, ENUM values are integers not strings.
You will have to use an if statement.
You could use a helper method:
WebServiceList.h
typedef NS_ENUM(NSUInteger, WebServiceList) {
WebServiceListNone = 0,
UserLoginComplexType = 1,
RegisterUserResult = 2,
RecoverPasswordResult = 3,
....
};
FOUNDATION_EXTERN WebServiceList WebServiceListForString(NSString *string);
WebServiceList.m
WebServiceList WebServiceListForString(NSString *string) {
WebServiceList list = WebServiceListNone;
if (![type isKindOfClass:[NSString class]]) {
return CallRecordTypeNone;
}
else if ([string isEqualToString:#"UserLoginComplexType"] {
list = UserLoginComplexType;
}
else if ([string isEqualToString:#"UserLoginComplexType"]) {
list = UserLoginComplexType;
}
else .....
return list;
}

As seen in your commented codes, you're parsing a XML and saving in a NSMutableArray named arrProductList in App Delegate.
After finishing the parsing of XML, the variable should contain the data in array. You should look into the variable & fetch the corresponding value. Since you didn't post any further details about parsing / XML structure, I'm unable to write some codes related to result fetching.

For easy readability and to avoid lots of if-else statements, I like to do mine as a dictionary:
(also makes it easy to update in the future when you add more to your enum)
NSString* elementName = ...;
// Default value
WebServiceList value = UserLoginComplexType;
NSDictionary* stringToEnum = #{#"UserLoginComplexType":#(UserLoginComplexType),
#"RegisterUserResult":#(RegisterUserResult),
#"RecoverPasswordResult":#(RecoverPasswordResult)};
NSNumber* enumValue = stringToEnum[elementName];
if(enumValue != nil)
value = (WebServiceList)enumValue.integerValue;

Related

Objective C: A cleaner way to check if a string isn't empty before creating and assigning a string to a dictionary key?

I am creating an NSMutableDictionary and assigning an NSString (test and test1) to a parameter key.
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
if (test.length) {
dictionary[#"test"] = test;
}
if (test1.length) {
dictionary[#"test1"] = test1;
}
This method does work. However, I am going to eventually have more strings and don't want a bunch of if statements. I don't want the dictionary keys to exist if the string is empty or nil.
Not sure if there is a way around this.
I thought about creating a separate function that accepts an array of key string and array of string values and use a for loop to see if string value is empty. Then, return a dictionary once the for loop ends. However, you can't insert nil into an NSArray
Something like this
- (void)updateDic:(NSMutableDictionary *)dic withString:(NSString *)str {
if (!str || [str isEqualToString:#""]) {
return;
}
dic[str] = str;
}
And then just iterate over all strings and use that method.
What I'd do is create a NSMutableDictionary category, something like this:
NSMutableDictionary+CustomMethods.m:
- (void)setStringIfNotNil:(NSString *)string forKey:(id <NSCopying>)key {
if (!string || !string.length) { return; }
self[key] = string;
}
Then you can use it like this:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setStringIfNotNil:test forKey:#"test"]
[dictionary setStringIfNotNil:test1 forKey:#"test1"]
There are three ways according to me..
The first one use the category in which you have to write if condition only single time and you can use it in any class of your project.
Second one by making a separate method to do that task(to check string nil or not and adding into the dictionary).
And the third one , just add all in an array and and perform the action in a loop.
The syntax:
dictionary[#"test"] = test
will remove the value from the dictionary if test is nil (it's a difference between the normal -setObject:forKey: method and the -setObject:forKeyedSubcript: which that syntax invokes). However, that will not work for empty strings.
As mentioned in another answer, you could make an NSDictionary category method to check, then call that method instead.
You could also just use the regular dictionary[key] = value syntax, then when you are done, do:
[dictionary removeObjectsForKeys:[dictionary allKeysForObject:#""]];
If it's possible to have the keys repeated, and you don't want an empty string overriding an earlier valid valid, you would have to check each time -- either by the category method, or using a local macro or inline function or local method.
static inline void SetValidVal(NSMutableDictionary *dictionary, NSString *key, NSString *val) {
if (val.length) { dictionary[key] = val; }
}
or
#define MY_SET_VALID_VAL(dictionary, key, val) if ((val).length) dictionary[key] = (val)
If the key names need to be the same as the name of the local variable, you can play other games with macros (this also assumes the local variable name "dictionary":
#define MY_UPDATE_VAL(val) if (val.length) dictionary[##val] = (val)
Then MY_UPDATE_VAL(test1); would expand to:
if (test1.length) dictionary[#"test1"] = test1;
That's a bit magic though and probably not recommended.

iOS: Is this a good way to check if JSON dictionary object is an NSString?

I want to check if a JSON object is an NSString and if it isn't, assign it a default string. My ultimate goal is to prevent crashing and assign the properties a proper value no matter what. This is an example of a data model I am using where dict is the JSON dictionary the API returns.
Data *data = [[self alloc] init];
data.name = [NSString validateString:dict[#"name"] defaultString:#""];
data.status = [NSString validateString:dict[#"status"] defaultString:#"OPEN"];
Here is the category method validateString I am using.
+ (NSString *)validateString:(NSString *)aString defaultString:(NSString *)defaultString {
if ([aString isKindOfClass:[NSString class]]) {
return aString;
}
return defaultString;
}
It makes no sense, and is very bad practice, to cast (NSString *)aString and then ask if this is in fact an NSString.
Also, what if it is nil?
All you know when you fetch from a dictionary is that you get an id. Do not assume more than that.
I would suggest writing very plainly: say what you mean, and mean what you say. That is the best practice in Objective-C. Otherwise, dynamic typing and "nil trickery" can lead you into subtle errors. You might not have any trouble in this particular case, but bad habits are bad habits, and it is best not to let them form in the first place. I'd rewrite like this:
+ (NSString *) checkType:(nullable id)obj defaultString:(NSString *)def {
if (obj == nil || ![obj isKindOfClass:[NSString class]]) {
return def;
}
return obj;
}
Like mentioned in other comments: if you want to prevent crashes, you also need to check if it's nil, specially if there is a chance to port your code to Swift in the future.
Just to clarify my last sentence, the line below works in Objective-C even if aString is nil:
if ([aString isKindOfClass:[NSString class]]) {
That's because, in the way Objective-C was made, calling a function on a nil object returns nil, so the if will be considered false, and the function will return defaultString. Yeah... that's certainly a bad idea when they created Objetive-C, since this leads to lots of errors. More details about that behaviour below:
https://stackoverflow.com/a/2696909
Anyway, it's also a good practice to only cast an object after checking its type, so I would recommend adapting your function to this:
+ (NSString *)validateString:(id)obj defaultString:(NSString *)defaultString {
if (obj != nil && [obj isKindOfClass:[NSString class]]) {
return (NSString*)obj;
}
return defaultString;
}
Every object that implements NSObject* has isKindOfClass: (and NSDictionary* only stores objects that implement NSObject*), so we don't need to check if the object responds to it. Also, even if we wanted, respondsToSelector: is also an NSObject* function.
Still, the method that you are using still works. The revised function above is just adapted to better practices and to avoid problems in case you ever need to port this code to Swift (or any other language) in the future.
EDIT: Updated code based in #matt's suggestion.

Expected method to read array element not found on object of type NSDictionary*

I know there's a lot of questions like this around, but I think my situation's a tad different.
int i = 0;
while (_data[#"VerticalState%i", i] != nil) {
// do things
i++;
}
For example, one 'level' that has 3 VerticalState properties will be implemented as such: VerticalState0, VerticalState1, VerticalState2.
I want to read in those values using that while loop condition above, and it should stop when i = 3. How can I make the idea of that code above work (with some other configuration obviously). FYI, _data is an NSDictionary* instance variable, already loaded with the plist information.
You appear to want to create a dictionary key from a string format. You need to use NSString stringWithFormat:.
while (_data[[NSString stringWithFormat:#"VerticalState%i", i]] != nil) {
Though it would be better to write the loop like this:
int i = 0;
while (1) {
NSString *key = [NSString stringWithFormat:#"VerticalState%i", i];
id value = _dict[key];
if (value) {
// do things
i++;
} else {
break;
}
}

Integer from .plist

I'm new to plists, and I really need to use one. What I have is a plist where different numbers are stored, under two dictionaries. I need to get that number which is stored, and make it an integer. This process will be run from a method called 'readPlist.
The plist is called 'properties.plist'. The first dictionary is called 'Enemies'. It contains various other dictionaries, which will have the name stored in the NSMutableString called 'SpriteType'. The name of the number will have the format 'L - %d', with the %d being an integer called 'LevelNumber'.
If possible, can someone give me the code on how to get that integer using the information, and the names of dictionaries above.
I have looked around at how to access plists, but the code that people have shown doesn't work.
Thanks in advance.
EDIT: Too make it more understandable, this is my plist. What i want in an integer, called 'SpriteNumber' to be equal to the value of 'L - %d'
If you read the contents of your plist into a dictionary (I won't tell you how to do it, but this is the tutorial I refer to often), then it's a matter of getting the string out of the key for the level with [[myDictionary objectForKey:#"key"]stringValue];. Then, using of NSString's extremely helpful -stringByReplacingOccurencesOfString:withString: to get rid of the "L -" part and only get a numerical value. Finally, get an integer from the string with [myString intValue].
well, the easiest way would be something like :
-(int) getMosquitoCountForLevel:(int) level {
int mosquitoCount=0;
NSString *gsFile = #"whateverFullyQualifiedFileNameYourPlistIs";
NSDictionary* definitions = [NSDictionary dictionaryWithContentsOfFile:gsFile];
NSDictionary* mosquitos = [definitions objectForKey:#"Mosquito"];
if(mosquitos) {
NSString *levelKey = [NSString stringWithFormat:#"L - %d",level];
NSNumber *mosquitoCountAsNumber = [mosquitos objectForKey:levelKey];
if(mosquitoCountAsNumber) {
mosquitoCount=[mosquitoCountAsNumber intValue];
} else {
CCLOGERROR(#"%# - Mosquito definitions in %# does not contain a en entry for level %#.",self.class,gsFile,levelKey);
}
} else {
CCLOGERROR(#"%# - file %# does not contain a Mosquito dictionary.",self.class,gsFile);
}
return mosquitoCount;
}
this compiles but not tested with actual data.

Enum, PList or some other storage?

iOS 5.0 SDK
I have a method that took a parameter as a 'type' that I defined. Lets call it 'Places'. This type was defined as the following:
typedef enum {
kBar = 0,
kRestaurant = 1,
kCafe = 2
} Places
My method would take a parameter of Places.
Based on the Place type passed in, I would append the type to the url:
ex: http://www.domain.com/place=1
However, the url parameter cannot be a number it has to be a string.
ex: http://www.domain.com/place=restaurant
I know enums cannot be strings so I am trying to figure out the right approach for this. Do I have a plist and then read the plist into a dictionary? Is there another way?
I would do something like:
typedef enum {
PlaceTypeBar = 0,
PlaceTypeRestaurant = 1,
PlaceTypeCafe = 2
} PlaceType
#interface PlaceTypeHelper : NSObject
+ (NSString *) stringForPlace:(PlaceType)place;
#end
#implementation
+ (NSString *) stringForPlace:(PlaceType)place {
NSArray *places = [NSArray arrayWithobjects:#"Bar", #"Restaurant", #"Cafe", nil];
return [places objectForKey:(NSInteger)place];
}
#end
Headups, I've no tested the code yet.
There's a lot of different approaches you could take. Here's what I might do myself.
Assuming there's a finite and known amount of values, you can do a simple function which returns the string for the given type :
(NSString*) StringForPlaceType(PlaceType thePlace) {
switch(thePlace) {
case kBar:
return #"Bar";
case kRestaurant:
return #"Restaurant";
case kCafe:
return #"Cafe";
default:
// ...
}
}
No need for an object or class unless you want for flexibility such as dynamic values and such.

Resources