Use variables as case constants in swich statement - objective-c

I'm trying to use a variable as the case match, however I get "Expression is not an integer in Objective-C.
Is it possible to use variable in switches in this manner?
int count = [array count];
switch ([number to check]) {
case 0:
//first statement
break;
case 1 ... (count -1):
//somewhere between 1 and the next to last statement
//Basically the middle
break;
case count:
//Last statement
default:
break;
}

Objective-C (and C) switch only supports a single primitive constant value for each case statement (or a range as pointed out in the answer by TwoStraws). You would be much better off writing your code using if/else:
if ([number to check] == 0) {
} else if ([number to check] >= 1 && [number to check] < count) {
} else if ([number to check] == count) {
} else {
}

Objective-C's switch statement does support ranges of values as you've seen, but doesn't support variable matches I'm afraid.
So, the below code is valid because I've used exact integers:
int numberOfKittens = 12;
NSString *kittenDescription;
switch (numberOfKittens) {
case 0 ... 5:
kittenDescription = #"Need more kittens";
break;
case 6 ... 10:
kittenDescription = #"That's a good number of kittens.";
break;
case 11 ... 20:
kittenDescription = #"Are you sure you can handle that many kittens?";
break;
default:
kittenDescription = #"You must really love kittens!";
}
…but trying to put a variable in place of any of those will fail.
If this is something you desperately want, consider using Swift because it has a much more expressive switch matching system. Here's that same code in Swift, now with a variable being used to match a case:
let upperLimit = 20
let numberOfKittens = 19
var kittenDescription = ""
switch (numberOfKittens) {
case 0 ... 5:
kittenDescription = "Need more kittens"
case 6 ... 10:
kittenDescription = "That's a good number of kittens."
case 11 ... upperLimit:
kittenDescription = "Are you sure you can handle that many kittens?"
default:
kittenDescription = "You must really love kittens!"
}

Related

Objective C reference to a variable

I have a list of variables that are named based on two digits then a word i.e. val11 or val26
I need to perform a check on whether a certain value for a variable is equal to the next variable i.e. that val32 == val33
I have the names of the first variables that I need to check in an NSArray (i.e val33)
I can then write a function to perform the check as a lot of long winded if statements
-(void)checkValues:(NSArray *)valueArray {
for (int x = 0; x < [valueArray count]; x++) {
tempStr = [offFiles objectAtIndex:x];
//split variable name
NSString *value = [tempStr substringWithRange:NSMakeRange(3,2];
int numValue= [value intValue];
//long winded if statement
if (numValue == 11) {
if(val11 == val12) {
//do something
}
}
if (numValue == 12) {
if(val12 == val13) {
//do something
}
}
.... etc
if (numValue == 87) {
if(val87 == val88) {
//do something
}
}
}
}
Is there any way I can remove the long winded if statement and replace it with a reference to the next variable so that no matter what variable name is in the array I can easily just check it against the next variable
Something like the excel command indirect
=INDIRECT(CONCATENATE("Cell!A",numValue + 1))
Unless there is some need for you to store your data in a set of discrete separate variables, this is clearly a situation were an array would work for you. This could be either a c-style array or one using NSArray - its up to you.
Using a c-style array (assuming 10 completely made up values):
int myValues[10] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }
Then your series of if statements can be reduced to one:
if (myValues[numValue] == myValues[numValue+1]) {
// so something
}
So if numValue is 3, it would compare myValues[3] and myValues[4] - essentially the same as comparing val3 and val4 in your scheme. Please note that arrays are zero based - the first value is accessed myValue[0] - so if your numbering scheme is 1-based then you need to subtract 1, e.g.:
if (myValues[numValue-1] == myValues[numValue]) {
// do something
}
Beside from the syntax bugs (like starting variable names with a number), what you are looking for is the switch() statement:
switch(a)
{
case 1: // if a is 1 do the following
printf("a is 1");
break;
case 2: // if a is 2
printf("a is 2");
break;
....
default: // if a was none of the cases before do this
printf("a sucks!!");
}
Notice that you always need a break; statement at the end of each case x:

Switch-Case Statement and Range of Numbers

Is there a way to use switch statement with ranges in Objective C (in XCode), hypothetically something like this:
- (NSString *)evaluate:(NSInteger)sampleSize
{
NSString returnStr;
switch (sampleSize)
{
case sampleSize < 10:
returnStr = #"too small!";
break;
case sampleSize >11 && sampleSize <50:
returnStr = #"appropriate";
break;
case sampleSize >50:
returnStr = #"too big!";
break;
}
return returnStr;
}
There is a GCC extension (which I assume is supported in Clang) that might be suitable for you. It allows you to use ranges in case statements. The full documentation is at http://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Case-Ranges.html#Case-Ranges - an example case statement from that page is
case 1 ... 5:
which would match (unsurprisingly) 1, 2, 3, 4, or 5.
No, switch statements are for constant values in most languages... The closest you can get is to flow the cases into one another like this:
switch(sampleSize)
{
case 0:
case 1:
case 2:
returnStr = #"too small!";
break;
}
Alternatively, this Question may help...
EDIT: I just thought of another way: you could "#define" that large list of cases in a .h file like this:
#define TOO_LOW case 0: \
case 1: \
case 2: \
case 3:
and then use it in a switch like so:
switch(sampleSize)
{
TOO_LOW
returnStr = #"too small!";
break;
}
Of course, thats not the cleanest solution. What's wrong with 3 "if/else's"?
- (NSString *)evaluate:(NSInteger)sampleSize
{
NSString returnStr;
switch (sampleSize)
{
// for sampleSize between 0 and 10
case 0 ... 10:
returnStr = #"too small!";
break;
// for sampleSize between 11 and 50
case 11 ... 50:
returnStr = #"appropriate";
break;
// for sampleSize above 50
case 50 :
case default:
returnStr = #"too big!";
break;
}
return returnStr;
}
Please Note: This is a solution i worked out but it will not count if sampleSize has h value less than 0.
Simply pass true in your switch statement like below code
- (NSString *)evaluate:(NSInteger)sampleSize {
NSString returnStr;
switch (true)
{
case sampleSize < 10:
returnStr = #"too small!";
break;
case sampleSize >11 && sampleSize <50:
returnStr = #"appropriate";
break;
case sampleSize >50:
returnStr = #"too big!";
break;
}
return returnStr;
}
This will solve your problem

Is value "in" some other values, in objective-c

Coming from an extremely spoiled family upbringing (turbo pascal, python, ruby) I'm a bit puzzled when it comes to doing all the household chores myself.
Yesterday was one of these days where I just did not find myself a solution. I had to check whether a value matches one of some other values.
x = some_function_return_value();
if x in (1,4,17,29,35):
That's how I used to write it. Now with Objective-C I obviously can't do that. And I searched the old google, but found no answer, and the old manual, and nothing there, so how do you do this in Objective-C, without doing something cranky like the following?
if (x == 1 || x == 4 || x == 17 || x == ...) {
Edited: in this case it is an (int), I know for NSArray and NSString there are methods for this
If it's about integer values, you can use switch:
switch (x) {
case 1:
case 4:
case 17:
case 29:
case 35:
do_something();
break;
}
Do not forget that in C/C++/Objective-C, the cases fall through to the next by default. You need to add break; statements to prevent that.
For non-integer values, you have to do long if statements with a lot of repetition as C doesn't provide syntactic sugar or features that many scripting languages have to abbreviate this.
Another way would be for example to prepare an array and then do:
if ([myArray containsObject:[NSNumber numberWithInteger:x]])
or even better, use an NSSet for that. This will work for most objects, for example it will also work with strings.
There is a fast enumeration syntax in objective C that uses "in" to loop over collections, however given it requires converting your int values to NSNumbers, it's probably easier to use C here
BOOL success = NO;
int size = 5
NSInteger numbers[size] = {1,4,17,29,35};
for (int i = 0; i < size; i++) {
if (yourValue == numbers[i]) {
success = YES;
break;
}
}
if (success) {
/* do your stuff */
}
admittedly not as nice as python...
Here's my silly program of the day:
bool int_exists_in_array(const int n, const int a[], const size_t elementCount) {
return (0 != elementCount) &&
(n == a[0] || int_exists_in_array(n, a + 1, elementCount - 1U));
}
so this:
if x in (1,4,17,29,35):
becomes:
const int a[] = { 1, 4, 17, 29, 35 };
if (int_exists_in_array(x, a, sizeof(a)/sizeof(a[0]))) {
...
}
You can use NSSet in addition with NSValue.

Objective-C Using an enum in switch statements, one's working but the other won't

I have a little dilemma here with a piece of code I wrote. I have to determine a facing based on a previous facing and a move.
I made a simple enum for the 4 facings :
typedef enum directions {N,E,S,W}Facing;
And then there are three functions, each working with a simple switch statement, taking an action based on the current facing. Now, the functions turnLeft and turnRight work just fine, but in the function move, the switch statement doesn't hit any of the cases, even though I know for sure either N,E,S, or W are entered.
- (Facing) turnLeft: (Facing) f
{
switch (f)
{
case N:
f = W;
break;
case E:
f = N;
break;
case S:
f = E;
break;
case W:
f = S;
break;
default:
break;
}
return f;
}
- (Facing) turnRight: (Facing) f
{
switch (f)
{
case N:
f = E;
break;
case E:
f = S;
break;
case S:
f = W;
break;
case W:
f = N;
break;
default:
break;
}
return f;
}
- (void) move:(Facing) f
{
switch (f)
{
case N:
y+1;
break;
case W:
x+1;
break;
case S:
y-1;
break;
case E:
x-1;
break;
default:
break;
}
}
So, as far as I know, all those switches work simmilarly, yet the third one is not working, the first two work perfectly fine. Does anyone have any idea what could be the problem?
The third switch statement is correct, as are the other two, but I think your problem is that it doesn't actually do anything. You compute y+1, x+1, y-1 or x-1 and then just throw the result away. Are you looking for e.g. x = x+1;?

How do I use a boolean operator in a case statement?

I just Don't understand how to use a boolean operator inside a switch statement
switch (expression) {
case > 20:
statements
break;
case < -20:
statements
break;
}
Edit:
I don't want an If () statement.
You can't. Use if() ... else ....
The nearest thing available to what you want uses a GCC extension and is thus non-standard. You can define ranges in case statements instead of just a value:
switch(foo)
{
case 0 ... 20: // matches when foo is inclusively comprised within 0 and 20
// do cool stuff
break;
}
However, you can't use that to match anything under a certain value. It has to be in a precise range. Switches can only be used to replace the comparison operator against a constant, and can't be used for anything more than that.
switch ((expression) > 20) {
case true:
statements
break;
case false:
default:
statements
break;
}
What.. you want more than 1 boolean in a case? You could do this
int ii = ((expression) > 20) + 2 * ((expression) < -20);
switch (ii) {
case 1:
statements
break;
case 2:
statements
break;
}
This, IMO is pretty bad code, but it is what you asked for...
Just use the if statement, you'll be better off in the long run.