objective C for-loop break and continue - iphone

How can i use a 'break' statement within a for-loop which continues form a specified label?
ex;
outer: for(int i = 0;i<[arABFBmatches count];i++){
for(int i = 0;i<[arABFBmatches count];i++){
//
break _____;
}
}
How to break to outer?

Hard to say from your question. I'd interpret it that you want to skip the rest of the iterations of the inner loop and continue the outer loop?
for (int i = 0; i < [arABFBmatches count]; i++) {
for (int j = 0; j < [arABFBmatches count]; j++) {
if (should_skip_rest)
break; // let outer loop continue iterating
}
}
Note that I changed the name of your inner loop invariant; using i in both is inviting insanity.
If you want to break from both loops, I wouldn't use a goto. I'd do:
BOOL allDoneNow = NO;
for (int i = 0; i < [arABFBmatches count]; i++) {
for (int j = 0; j < [arABFBmatches count]; j++) {
if (should_skip_rest) {
allDoneNow = YES;
break;
}
}
if (allDoneNow) break;
}

Roughly:
for(int i = 0;i<[arABFBmatches count];i++){
for(int j = 0;j<[arABFBmatches count];j++){
//
goto outer_done;
}
}
outer_done:
Objective-C does not have labelled break.

From Apple's Objective-C docs:
Objective-C is defined as a small but powerful set of extensions to
the standard ANSI C language.
So break and continue can be used wherever they are permitted in C.
continue can be used in looping constructs (for, while and do/while loops).
break can be used in those same looping constructs as well as in switch statements.

BOOL done = NO;
for(int i = 0;i<[arABFBmatches count] && !done; i++)
{
for(int i = 0;i<[arABFBmatches count] && !done;i++)
{
if (termination condition)
{
// cleanup
done = YES;
}
}
}

'break' will only get you out of the innermost loop or switch. You can use 'return' to exit out of a function at any time.Please have a look at the this link.

Related

how to synchronise removal of b2bodies when firing in game

In my game i have some monsters and my hero. when i fire some bullets i remove bodies on collision either with monster or ground body, and also added a timer event to remove the bullet as
-(void) removeProjectile:(CCPhysicsSprite*)projectile{
dispatch_time_t removeProjectile = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1* NSEC_PER_SEC));
dispatch_after(removeProjectile, dispatch_get_main_queue(), ^(void){
int i;
for(i=0;i<deadBodyCount;i++)
{
if(deadBodies[i] == projectile.b2Body)
{
break;
}
}
if(i==deadBodyCount)
{
deadBodies[deadBodyCount]=projectile.b2Body;
deadBodyCount++;
}
});
}
but what happens my code crashes, don't know. please help me. If you have any approach to do this.
i am removing deadbodies in
-(void)removeDeadBodies{
for (int i=0; i<deadBodyCount; i++) {
if(deadBodies[i]){
if([self getPSTag:deadBodies[i]]==3){
CCPhysicsSprite *temp=(CCPhysicsSprite *)deadBodies[i]->GetUserData();
NSLog(#"%#",temp);
[[self getChildByTag:kTagParentNode]removeChild:temp cleanup:YES];
}
else if([self getPSTag:deadBodies[i]]==2){
for (int j=0; j<monsterCount; j++) {
if (monsters[j].b2Body==deadBodies[i]) {
[[self getChildByTag:kTagParentNode]removeChild:monsters[j] cleanup:YES];
monsters[j]=NULL;
}
}
}
_world->DestroyBody(deadBodies[i]);
deadBodies[i]=NULL;}
}
deadBodyCount=0;
}
-(int)getPSTag:(b2Body *)body{ //physics sprite tag value from a b2Body
CCPhysicsSprite *sprite=(CCPhysicsSprite*)body->GetUserData();
//Here is the error------------------------------------
if(sprite)
return (int)sprite.tag;
else
return 0;
}
and this is my begin contact method
-(void)beginContact:(b2Contact *)contact{
b2Body *bodyA=contact->GetFixtureA()->GetBody();
b2Body *bodyB=contact->GetFixtureB()->GetBody();
int collideCheck=[self checkForCollisionGroups:bodyA And:bodyB];
if(!collideCheck)
return;
switch (collideCheck) {
case 1:
for (int i=0; i<monsterCount; i++) {
if(monsters[i].isVisible){
//Checking if Projectile hitting the monster
//bodyA is monster and bodyB is projectile
if([self getPSTag:bodyA]==2&&[self getPSTag:bodyB]==3){
[monsters[i] monsterHit];
[self doExplosionAtPoint:monsters[i].position];
deadBodies[deadBodyCount++]=monsters[i].b2Body;
CCPhysicsSprite *x=(CCPhysicsSprite *)bodyB->GetUserData();
for (int i=0; i<10; i++) {
if(deadBodies[i]==x.b2Body)
return;
}
deadBodies[deadBodyCount++]=x.b2Body;
[self.top updateScore:100];
}//bodyA is Projectile and bodyB is Monster
else if([self getPSTag:bodyA]==3&&[self getPSTag:bodyB]==2){//if one of the body is projectile
[monsters[i] monsterHit];
[self doExplosionAtPoint:monsters[i].position];
CCPhysicsSprite *x=(CCPhysicsSprite *)bodyA->GetUserData();
for (int i=0; i<10; i++) {
if(deadBodies[i]==x.b2Body)
return;
}
deadBodies[deadBodyCount++]=x.b2Body;
deadBodies[deadBodyCount++]=monsters[i].b2Body;
[self.top updateScore:100];
}
}
}
break;
case 2:
if (jumping==YES) {
jumping=NO;
}
break;
case 3: //bullet hitting with any object
if([self getPSTag:bodyA]==3){//if one of the body is projectile
CCPhysicsSprite *x=(CCPhysicsSprite *)bodyA->GetUserData();
for (int i=0; i<10; i++) {
if(deadBodies[i]==x.b2Body)
return;
}
deadBodies[deadBodyCount++]=x.b2Body;
}
else if ([self getPSTag:bodyB]==3){
CCPhysicsSprite *x=(CCPhysicsSprite *)bodyB->GetUserData();
for (int i=0; i<10; i++) {
if(deadBodies[i]==x.b2Body)
return;
}
deadBodies[deadBodyCount++]=x.b2Body;
}
break;
case 4:
for (int i=0; i<monsterCount; i++) {
if(monsters[i].isVisible){
if( (bodyA==monsters[i].b2Body&&bodyB==_heroBody)||(bodyA==_heroBody&&bodyB==monsters[i].b2Body)) {
_heroBody->SetLinearVelocity(b2Vec2(-3*hero.scaleX, 5));
lifeCount=[_top updateHealthMeterWithDamage:10];
NSLog(#"collide");
moving=false;
}
}
}
break;
/*case 6:if([self getPSTag:bodyA]==33){
movingTile.position=((CCSprite*)bodyA->GetUserData()).position;
}
else
movingTile.position=((CCSprite*)bodyB->GetUserData()).position;*/
default:
break;
}
}
I looked at your code. I dont understand the use of removeProjectile: CCPhysicsSprite*)projectile{} method while you indirectly actually adding the projectiles to the deadBodies[] in the beginContact(). So i guess here you have two pointers pointing to same body. And when you run the removeDeadBodies() for loop, it actually first deletes the body and then in next iteration when again it gets the dangling pointer with no body then it crashes.
I commented the line [self removeProjectile:projectile]; in the createProjectileAt() method. And now everything is working fine.
I know it might be late to implement but a suggestion, to have better hold on your b2Bodies and safe deletion from world, you can take a struct datatype with data members as a Sprite and a BOOL variable say isDelete. And use this struct as the userdata of the body. So now you can just set this bool variable to YES inside beginContact() call back. And in you update: tick method after the world->step is over just iterate through the world of bodies and check the BOOL var that can be deleted. HEre you can safely delete the bodies. No need to maintain an array of deadBodies etc. Hence there will not be any synchronization issue.

making my own tile system cause lag

- (void) loadStartingTiles //16 by 24
{
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:
#"clonespritesheet.plist"];
for(int x = 0; x < 16; x++) //minus 1 for one at the begining
{
for(int y = 0; y < 26; y++)
{
CCSprite *tempsprite;
switch (currentscreen[x][y])
{
case 0:
tempsprite = [CCSprite spriteWithSpriteFrameName:#"block0.png"];
break;
case 1:
tempsprite = [CCSprite spriteWithSpriteFrameName:#"block1.png"];
break;
}
tempsprite.position = ccp(y*20+10,(16-x)*20-10); //+10 for align for tile size
[self addChild:tempsprite z:3];
[tiles addObject:tempsprite];
}
}
}
So I make a bunch of sprites from an int array that tells them where they should be then i add them into the nsmutable array tile. then i move everything in the array to the left slowly, and im losing around 20 FPS. what is a more efficient way to make a tile system? my goal is to make randomly generated tiles later on.
- (void) manageTiles:(CGFloat)dt
{
int tileamount = [tiles count];
for(int i = 0; i < tileamount; i++)
{
CCSprite *tempsprite = [tiles objectAtIndex:i];
tempsprite.position = ccp(tempsprite.position.x-20*dt,tempsprite.position.y);
}
}
EDIT: the awnser is
int themap = -20;
- (void) manageTiles:(CGFloat)dt
{
tiles.position = ccp(tiles.position.x-10*dt,tiles.position.y);
NSLog(#"%d",themap);
if(tiles.position.x < themap)
{
CCSprite *tempsprite;
for(int i = 0; i < 16; i++)
{
[tiles removeChildAtIndex:0 cleanup:YES];
}
for(int i = 0; i < 16; i++)
{
switch (tilewall[i])
{
case 0:
tempsprite = [CCSprite spriteWithSpriteFrameName:#"block1.png"];
break;
case 1:
tempsprite = [CCSprite spriteWithSpriteFrameName:#"block1.png"];
break;
}
tempsprite.position = ccp((themap*-1)+500+10,((16-i)*20-10));
[tiles addChild:tempsprite];
}
themap = themap-20;
}
}
Where you are going wrong is, you are not using a CCSpriteBatchNode. A CCSpriteBatchNode will draw all of the tiles in one draw operation instead of doing one draw operation per tile. The drawbacks are, each tile in the batch node will have the same zOrder (in a way), and it all must use one source spritesheet per batch node. SO basically if you wanted different layers at different zOrders, or different layers which use different source images for the tiles, you would have to create multiple batch nodes, one for each.
http://www.cocos2d-iphone.org/api-ref/0.99.5/interface_c_c_sprite_batch_node.html
Preload the tempsprite variable outside your loop:
CSprite *sprite0 = [CCSprite spriteWithSpriteFrameName:#"block0.png"];
CSprite *sprite1 = [CCSprite spriteWithSpriteFrameName:#"block1.png"];
And then refer them to them in the loop:
switch (currentscreen[x][y])
{
case 0:
tempsprite = sprite0;
break;
case 1:
tempsprite = sprite1;
break;
}
or even better:
tempsprite = currentscreen[x][y] ? sprite1 : sprite0;
Oh, and your inner loop should refer to 24, not 26.

Calling methods with specific values

For this code example below, usually I would use [self fall]; instead of the code at *, but I need the value of i to be sent to the fall method as well. How do I do this?
- (void)main {
for (int i=0; i <= 100; i++) {
[image[i] fall]; *
}
}
- (void)fall {
// manipulate image[i]; separately from the for loop
}
EDIT: I will accept the oldest answer as all are correct. Thanks!
You need to do -
- (void)fall:(int)i {
// manipulate image[i]; separately from the for loop
}
and call like -
- (void)main {
for (int i=0; i <= 100; i++) {
[image fall:i];
}
}
EDIT -
If you want to pass index-
- (void)fall:(int)i {
// manipulate image[i]; separately from the for loop
}
and call like -
- (void)main {
for (int i=0; i <= 100; i++) {
[self fall:i]; // Now from here you can either pass index
}
}
If you want to pass some image -
- (void)fall:(UIImage)i {
// manipulate image[i]; separately from the for loop
}
and call like -
- (void)main {
for (int i=0; i <= 100; i++) {
[self fall:imageI]; // Now from here you need to pass image, if that image is stored in array, then fetch from array. Or you need to manipulate in the way in which you are storing.
}
}
Maybe you mean:
- (void)main {
for (int i=0; i <= 100; i++) {
[image[i] fall:i];
}
}
- (void)fall:(int)i {
// manipulate image[i]; separately from the for loop
}
Or, maybe you mean:
- (void)main {
for (int i=0; i <= 100; i++) {
[self fall:image[i]];
}
}
- (void)fall:(NSImage *)image {
// manipulate image[i]; separately from the for loop
}
If not, you need to clarify your question.

Problem with Objective-C for loop

I have two methods, the generateRandomCard method gets called within the testMethod, where there is a for loop that runs 100 times. That way it works perfect, but if I set the for loop limit to 1000 or any other number greater than 100 it crashes. Can you see what's wrong??
- (void)testMethod {
Globals *myGlobals = [Globals sharedInstance];
int rankOfFirst = 0;
int rankOfSecond = 0;
int playerOneWin = 0;
int playerTwoWin = 0;
int ties = 0;
float firstPercent = 0;
float secondPercent = 0;
float tiePercent = 0;
FiveEval *evaluator = [FiveEval theEvaluator];
for (int i = 0; i < 100; i++) {
short fPF = [self generateRandomCard];
short fPS = [self generateRandomCard];
short sPF = [self generateRandomCard];
short sPS = [self generateRandomCard];
short fFlop = [self generateRandomCard];
short sFlop = [self generateRandomCard];
short tFlop = [self generateRandomCard];
short tur = [self generateRandomCard];
short riv = [self generateRandomCard];
rankOfFirst = [evaluator getRankOfSeven:fFlop
:sFlop
:tFlop
:tur
:riv
:fPF
:fPS];
rankOfSecond = [evaluator getRankOfSeven:fFlop
:sFlop
:tFlop
:tur
:riv
:sPF
:sPS];
if (rankOfFirst > rankOfSecond) {
playerOneWin++;
} else if (rankOfSecond > rankOfFirst) {
playerTwoWin++;
} else {
ties++;
}
[myGlobals.alreadyPickedCards removeAllObjects];
}
firstPercent = ((float)playerOneWin/(float)10000)*100;
secondPercent = ((float)playerTwoWin/(float)10000)*100;
tiePercent = ((float)ties/(float)10000)*100;
NSLog(#"First Player Equity: %f", firstPercent);
NSLog(#"Second Player Equity: %f", secondPercent);
NSLog(#"Tie Equity: %f", tiePercent);
}
- (short)generateRandomCard {
Globals *myGlobals = [Globals sharedInstance];
short i = arc4random()%51;
for (int j = 0; j < [myGlobals.alreadyPickedCards count]; j++) {
if (i == [[myGlobals.alreadyPickedCards objectAtIndex:j] shortValue]) {
[self generateRandomCard];
}
}
[myGlobals.alreadyPickedCards addObject:[NSNumber numberWithShort:i]];
return i;
}
You're probably overflowing your stack in the recursive call to -generateRandomCard. If you generate a card that's already been picked, you call yourself recursively (and ignore the result, which is a different bug). So, if your random number stream gave you an unlucky sequence that kept returning cards you've already picked, then you'll recurse infinitely until the stack overflows.
Change your card selection algorithm so that instead of using rejection sampling with the potential for infinite looping/recursion, it uses an algorithm with a bounded runtime such as the Fisher-Yates shuffle.
Not sure if this could in any way lead to the crash - It may be unrelated. However, it does look like you have a bug in the way you recursively call generateRandomCard when a card is found in the alreadyPickedCards array. Instead of
[self generateRandomCard];
I think you should have
return [self generateRandomCard];
You have in -testMethod:
[myGlobals.alreadyPickedCards removeAllObjects];
and in -generateRandomCard you have:
for (int j = 0; j < [myGlobals.alreadyPickedCards count]; j++) {
if (i == [[myGlobals.alreadyPickedCards objectAtIndex:j] shortValue]) {
[self generateRandomCard];
}
}
I can't bet for sure, but this looks like a situation where you removeAllObjects in 1 loop and access an out of bound index in another loop.
If you wanna play like this with arrays, I suggest you make copies of arrays and remove items from those copied arrays.

For loop and if statement

I am working with the following for loop:
for (int intPrjName = 0; intPrjName < [arrPrjName count]; intPrjName++)
I have a if/else statement under the for loop, in which the else block shows an alert message. Suppose array count is 10; then when the if fails, the else block will execute ten times, and the alert message displays ten times. How can I deactivate this?
Your problem is a general programing problem. The simplest way is to just use a BOOL flag.
BOOL alertShown = NO;
for (int intPrjName = 0; intPrjName < [arrPrjName count]; intPrjName++) {
if (something) {
// . . .
} else {
if (!alertShown) {
[self showAlert:intPrjName]; // Or something
alertShown = YES;
}
}
}
If you want to show only one alert in case of failed condition that would probably mean you don't want to continue the loop. So as Jason Coco mentioned in his comment, you break from the loop. Here's a simple example on how to do this:
for (int intPrjName = 0; intPrjName < [arrPrjName count]; intPrjName++) {
if (condition) {
// do something
} else {
break;
}
}
Otherwise, if you want to check some condition for every element of the array, you would probably want to keep track of failures and show user the summary (could be an alert message, another view, etc). Short example:
NSUInteger numFailures = 0;
for (int intPrjName = 0; intPrjName < [arrPrjName count]; intPrjName++) {
if (condition) {
// do something
} else {
numFailures++;
}
}
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title
message:#"Operation failed: %d", numFailures
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil] autorelease];
[alert show];
Good luck!
Assume C is an Array where n is an int or NSNumber type caste to int
for(n in C){
if{n equal to 10)
dostuff
}
else{
doOtherStuff
}
}
}
The good thing about this approach you can inore the size of the Array.
Look at the docs for Enumeration Glass