So I have created a switch statement inside another switch statement for certain sections and rows, quite hard to explain so have a look at the actual code. Anyways I was wondering if such patter should be avoided or if it does not really matter, I am new to stackoverflow as you may have already noticed so I am not entirely sure this question has been asked before.
switch(indexPath.section) {
case 0: {
switch ([indexPath row]) {
case 0: {
[self.navigationController pushViewController:introductionViewController animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
break;
}
case 1: {
[self.navigationController pushViewController:matterViewController animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
break;
}
break;
}
case 1: {
break;
}
}
}
A switch statement inside of a switch statement is perfectly legal. There's nothing inherently wrong with it, though it may be difficult to follow if there are many cases in either statement. One solution is to make the inner switch statement into a separate function or method. For example, if you have this:
switch (a)
{
case foo:
switch (b)
{
case bar:
doSomething();
break;
case bas:
doSomethingElse();
break;
}
break;
case foo2:
...whatever
}
You could do it like this:
void handleFoo (int x)
{
switch (x)
{
case bar:
doSomething();
break;
case bas:
doSomethingElse();
break;
}
}
...
main ()
{
...
switch (a)
{
case foo:
handleFoo(b);
break;
case foo2:
...whatever;
break;
}
}
Related
It seems that all of the examples for GameplayKit are always in Swift. I've decided not to move over to swift for now and I've just been translating a lot of code into Objective C, which is fine most of the time.
I'm trying to implement the isValidNextState method from the GKState class, but I'm getting an error for the switch statement and I'm not sure what it wants...it seems in Swift this is fine, but not in obj C. The error that I'm getting is:
Error: Statement requires expression of integer type('__unsafe_unretained Class _Nonnull' invalid
What should I have in the switch statement instead of stateclass?
-(BOOL) isValidNextState:(Class)stateClass {
switch (stateClass) { //ERROR ON THIS LINE
case [InvulnerableState class]: //not sure what this should be either
return YES;
break;
default:
break;
}
return NO;
}
Here's the equivalent in Swift which works fine:
override func isValidNextState(stateClass: AnyClass) -> Bool {
switch stateClass {
case is InvulnerableState.Type:
return true
default:
return false
}
}
Your isValidNextState method should be:
- (BOOL)isValidNextState:(Class)stateClass {
return stateClass == [InvulnerableState class];
}
And if you have multiple next valid states, it should be, for example:
- (BOOL)isValidNextState:(Class)stateClass {
return stateClass == [InvulnerableState class] ||
stateClass == [InvulnerableState2 class];
}
so my issue is happening only when I have two enemies on a team in my game. If it's a one versus one.. I do not get the issue.
Please look at my code and see if you can gather as to why I'm getting this fatal error.
Removes Target from players target array
-(void)removeTarget:(PlayerClass *)target withSender:(PlayerClass *)sender {
if ([sender.targets containsObject:target]) {
[sender.targets removeObject:target];
}
}
Adds Target to players target array
-(void)addTarget:(PlayerClass *)target withSender:(PlayerClass *)sender {
//check if target already exists
if ([sender.targets count] > 0) {
for (PlayerClass *players in sender.targets) {
if ([players.name isEqualToString:target.name]) {
//Checked if exists, if target exists in list then move on.
goto outer;
}
}
}
[sender.targets addObject:target];
outer:;
}
In the Update to determine whether they're a target or not
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
for (PlayerClass *player in _players) {
....
if (player.health > 0) { //If player is alive!
....
//Checks if the player has targets, if so & visible - Engage.
if ([player.targets count] > 0) {
for (PlayerClass *enemy in player.targets) {
if (![player.team isEqualToString:enemy.team]) {
if (enemy.health > 0) {
if ([self lineOfSightBetweenPlayers:player andPlayer:enemy]) {
[self attackWithPlayer:player againstPlayer:enemy];
break;
} else {
[player removeTarget:enemy withSender:player];
}
} else {
[player removeTarget:enemy withSender:player];
}
} else {
[player removeTarget:enemy withSender:player];
}
}
}
}
Now from debugging I've gathered that the players don't add their team mates as targets. However, the player will gather more than one target if they can see more than one target on the opposing team. However, the issue I'm guessing lies in my technique to removing a target from the array? Can anyone check over and make sure I'm not delivering a school boy error here?
Thanks in advance.
Very simple fix. Wasn't thinking outside the box.. which tends to happen when code starts getting very large!
//Checks if the player has targets, if so & visible - Engage.
if ([player.targets count] > 0) {
for (PlayerClass *enemy in player.targets) {
if (![player.team isEqualToString:enemy.team]) {
if (enemy.health > 0) {
if ([self lineOfSightBetweenPlayers:player andPlayer:enemy]) {
[self attackWithPlayer:player againstPlayer:enemy];
break;
} else {
[player removeTarget:enemy withSender:player];
break;
}
} else {
[player removeTarget:enemy withSender:player];
break;
}
} else {
[player removeTarget:enemy withSender:player];
break;
}
}
}
Fixed my issue, I wasn't breaking out. Thus enumerating after removal.
This question already has an answer here:
Defining a block in a switch statement results in a compiler error
(1 answer)
Closed 7 years ago.
This is a switch statement that I am getting errors on:
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
// show wait view here
statusLabel.text = #"Processing...";
break;
case SKPaymentTransactionStatePurchased:
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
// remove wait view and unlock iClooud Syncing
statusLabel.text = #"Done!";
NSError *error = nil;
[SFHFKeychainUtils storeUsername:#"IAPNoob01" andPassword:#"whatever" forServiceName: kStoredData updateExisting:YES error:&error];
// apply purchase action - hide lock overlay and
[oStockLock setBackgroundImage:nil forState:UIControlStateNormal];
// do other thing to enable the features
break;
case SKPaymentTransactionStateRestored:
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
// remove wait view here
statusLabel.text = #"";
break;
case SKPaymentTransactionStateFailed:
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"Error payment cancelled");
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
// remove wait view here
statusLabel.text = #"Purchase Error!";
break;
default:
break;
}
The last two cases, plus the default, are giving me the following error:
Cannot jump from switch statement to this case label
I have used the switch statement many, many times; this is the first time I have seen this. The code has been copied from a tutorial (here), which I am trying to adapt for my app. Would appreciate the help on this one. SD
C is not Swift. You'll be happier if you structure your switch statements using curly braces round all of the cases interiors, like this:
switch (tag) {
case 1: { // curly braces
// ...
break;
}
case 2: { // curly braces
// ...
break;
}
case 3: { // curly braces
// ...
break;
}
}
The extra level of curly braces allows you to do things you can't do otherwise.
I have a switch statement like this:
switch (int) {
case 0:
// do x
break;
case 1:
// do y
break;
default:
break;
}
Can I get the case number?
The reason I ask is that I have a method in each one that would use a variable int. For example:
switch (int) {
case 0:
[self doMethod:string setTag: <CASE NUMBER> ];
break;
case 1:
[self doMethod:string setTag: <CASE NUMBER> ];
break;
default:
break;
}
Is there any way to do this?
Thanks!
switch (x) {
case 0:
// if you're here, you know x == 0
[self doMethod:string setTag: x];
break;
...
}
But unless string is a different variable or literal in each case, this doesn't make much sense; you could as easily say
if (x == 0 || x == 1) {
[self doMethod: string setTag: x];
}
First off, you can't do switch (int). int is a data type. You need a variable in there.
Then all you need to do is reference the variable in the case statement:
int someVar = ... // some value
switch (someVar) {
case 0:
[self doMethod:string setTag:someVar];
break;
case 1:
[self doMethod:string setTag:someVar];
break;
}
BTW - if you do the same thing for multiple cases you can do:
int someVar = ... // some value
switch (someVar) {
case 0:
case 1:
[self doMethod:string setTag:someVar];
break;
default:
// other stuff
break;
}
And as Josh pointed out, depending on your needs, this whole thing could simply be:
int someVar = ... // some value
[self doMethod:string setTag:someVar];
or maybe:
int someVar = ... // some value
if (someVar >= 0 && someVar <= 1) {
[self doMethod:string setTag:someVar];
}
switch (indexPath.section) {
case 0: //products used
NSString * chemical = [selectedChemicals objectAtIndex:indexPath.row];
cell.textLabel.text = chemical;
break;
case 1: //areas sprayed
return [selectedAreas count];
break;
case 2://target pests
return [selectedPests count];
break;
case 3://notes
return 1;
break;
}
gives me: "/Users/grady/programming/ObjectivelyBetter/bioguard/Classes/JobWizardViewController.m:147: error: 'chemical' undeclared (first use in this function)"
putting a blank semi-colon at the beginning of the case fixes it.
switch (indexPath.section) {
case 0: //products used
;
NSString * chemical = [selectedChemicals objectAtIndex:indexPath.row];
cell.textLabel.text = chemical;
break;
case 1: //areas sprayed
return [selectedAreas count];
break;
case 2://target pests
return [selectedPests count];
break;
case 3://notes
return 1;
break;
}
When you declare variables within a case statement, it's a good practice (and required to avoid these kinds of errors) to enclose the statements inside curly braces, e.g.
case 0:
{
int i = 0;
....
break;
}
Not sure why a semicolon along would have "solved" the issue. That's kind of odd... the curly braces are what you need.
In your particular case you could also just eliminate the local variable declaration and set the cell textLabel like so:
cell.textLabel.text = [selectedChemicals objectAtIndex:indexPath.row];