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
Related
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.
I'm following the Stanford course, and we had to build a method for the app that checks for 2 cards matching, this is how the model that have the logic looks like (the method to look there is flipCardAtIndex):
#import "CardMatchingGame.h"
#import "PlayingCardsDeck.h"
#interface CardMatchingGame()
#property (readwrite, nonatomic) int score;
#property (strong, nonatomic) NSMutableArray *cards;
#property (strong, nonatomic) NSString *notification;
#end
#implementation CardMatchingGame
-(NSMutableArray *) cards {
if (!_cards) _cards = [[NSMutableArray alloc] init];
return _cards;
}
-(id)initWithCardCount:(NSUInteger)count usingDeck:(Deck *)deck {
self = [super init];
if (self) {
for (int i = 0; i < count; i++) {
Card *card = [deck drawRandonCard];
if (!card) {
self = nil;
} else {
self.cards[i] = card;
}
}
}
return self;
}
-(Card *) cardAtIndex:(NSUInteger)index {
return (index < self.cards.count) ? self.cards[index] : nil;
}
#define FLIP_COST 1
#define MISMATCH_PENALTY 2
#define BONUS 4
-(void) flipCardAtIndex:(NSUInteger)index {
Card *card = [self cardAtIndex:index];
if (!card.isUnplayable) {
if (!card.isFaceUp) {
for (Card *otherCard in self.cards) {
if (otherCard.isFaceUp && !otherCard.isUnplayable) {
int matchScore = [card match:#[otherCard]];
if (matchScore) {
otherCard.unplayble = YES;
card.unplayble = YES;
self.notification = [NSString stringWithFormat:#"%# & %# match!", card.contents, otherCard.contents];
self.score += matchScore * BONUS;
} else {
otherCard.faceUp = NO;
self.score -= MISMATCH_PENALTY;
self.notification = [NSString stringWithFormat:#"%# did not matched to %#", card.contents, otherCard.contents];
}
break;
}
}
self.score -= FLIP_COST;
}
card.faceUp = !card.isFaceUp;
}
}
#end
And this is the class model of the whole game, that got the actual matching method:
#import "PlayingCards.h"
#implementation PlayingCards
#synthesize suit = _suit;
//overriding the :match method of cards to give different acore if its only a suit match or a number match
-(int)match:(NSArray *)cardToMatch {
int score = 0;
if (cardToMatch.count == 1) {
PlayingCards *aCard = [cardToMatch lastObject];
if ([aCard.suit isEqualToString: self.suit]) {
score = 1;
} else if (aCard.rank == self.rank) {
score = 4;
}
}
return score;
}
//more stuff...
W already created it with an array so we will be able to extend it for more objects, but now i'm trying to figure out how do I extend it :/
This is my github for the project https://github.com/NirOhayon/Matchismo
i'm new to objective C and would appreciate it munch if you could help me to figure it out.
Thanks a bunch
You can chain these with a loop to check them all. Very basic way of doing it. Just loop through each card and check it against the "self" card that you have and increment the score instead of setting it.
-(int)match:(NSArray *)cardToMatch {
int score = 0;
for(int i = 0; i < cardToMatch.count; i++) {
PlayingCards *aCard = cardToMatch[i];
if ([aCard.suit isEqualToString: self.suit]) {
score += 1;
} else if (aCard.rank == self.rank) {
score += 4;
}
}
return score;
}
For flipCardAtIndex: , I would change it to flipCardsAtIndexes:(NSArray*)indexes, where indexes is an NSArray of NSNumbers. Then I would run a for loop checking and removing any cards that are unplayable or faceup, and pass through the remaining cards at those indexes to check match, and retrieve the match score.
To tell your view controller to add another card depends on how you have your view controller set up. You could do a protocol in a method that your view controller becomes the delegate of, and through a protocol method, tell it to switch. It could also be simpler than that, depending on how it checks your model of cards to decide what to show, if it sees three cards available instead of two, it could switch.
As the point of this exercise is to learn iOS programming, I want to give you a good head start and you should tweak and figure some stuff out on your own. I have a feeling you're a novice at programming, and if you are, you'll be surprised how much programming at your stage is trial and error. Eventually it will become second nature.
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.
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.
I'm a beginner level programmer trying to make a game app for the iphone and I've encountered a possible issue with the memory management (exc_bad_access) of my program so far. I've searched and read dozens of articles regarding memory management (including apple's docs) but I still can't figure out what exactly is wrong with my codes. So I would really appreciate it if someone can help clear up the mess I made for myself.
//in the .h file
#property(nonatomic,retain) NSMutableArray *fencePoleArray;
#property(nonatomic,retain) NSMutableArray *fencePoleImageArray;
#property(nonatomic,retain) NSMutableArray *fenceImageArray;
//in the .m file
- (void)viewDidLoad {
[super viewDidLoad];
self.gameState = gameStatePaused;
fencePoleArray = [[NSMutableArray alloc] init];
fencePoleImageArray = [[NSMutableArray alloc] init];
fenceImageArray = [[NSMutableArray alloc] init];
mainField = CGRectMake(10, 35, 310, 340);
..........
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(gameLoop) userInfo:nil repeats:YES];
}
So basically, the player touches the screen to set up the fences/poles
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if(.......) {
.......
}
else {
UITouch *touch = [[event allTouches] anyObject];
currentTapLoc = [touch locationInView:touch.view];
NSLog(#"%i, %i", (int)currentTapLoc.x, (int)currentTapLoc.y);
if(CGRectContainsPoint(mainField, currentTapLoc)) {
if([self checkFence]) {
onFencePole++;
//this 3 set functions adds their respective objects into the 3 NSMutableArrays using addObject:
[self setFencePole];
[self setFenceImage];
[self setFencePoleImage];
.......
}
}
else {
.......
}
}
}
}
The setFence function (setFenceImage and setFencePoleImage is similar to this)
-(void)setFencePole {
Fence *fencePole;
if (!elecFence) {
fencePole = [[Fence alloc] initFence:onFencePole fenceType:1 fencePos:currentTapLoc];
}
else {
fencePole = [[Fence alloc] initFence:onFencePole fenceType:2 fencePos:currentTapLoc];
}
[fencePoleArray addObject:fencePole];
[fencePole release];
and whenever I press a button in the game, endOpenState is called to clear away all the extra images(fence/poles) on the screen and also to remove all existing objects in the 3 NSMutableArray. Point is to remove all the objects in the NSMutableArrays but keep the array itself so it can be reused later.
-(void)endOpenState {
........
int xMax = [fencePoleArray count];
int yMax = [fenceImageArray count];
for (int x = 0; x < xMax; x++) {
[[fencePoleImageArray objectAtIndex:x] removeFromSuperview];
}
for (int y = 0; y < yMax; y++) {
[[fenceImageArray objectAtIndex:y] removeFromSuperview];
}
[fencePoleArray removeAllObjects];
[fencePoleImageArray removeAllObjects];
[fenceImageArray removeAllObjects];
........
}
The crash happens here at the checkFence function.
-(BOOL)checkFence {
if (onFencePole == 0) {
return YES;
}
else if (onFencePole >= 1 && onFencePole < currentMaxFencePole - 1) {
CGPoint tempPoint1 = currentTapLoc;
CGPoint tempPoint2 = [[fencePoleArray objectAtIndex:onFencePole-1] returnPos]; // the crash happens at this line
if ([self checkDistance:tempPoint1 point2:tempPoint2]) {
return YES;
}
else {
return NO;
}
}
else if (onFencePole == currentMaxFencePole - 1) {
......
}
else {
return NO;
}
}
So the problem here is, everything works fine until checkFence is called the 2nd time after endOpenState is called. So its like tap_screen -> tap_screen -> press_button_to_call_endOpenState -> tap screen -> tap_screen -> crash
What I'm thinking of is that fencePoleArray got messed up when I used [fencePoleArray removeAllObjects] because it doesn't crash when I comment it out. It would really be great if someone can explain to me what went wrong. And thanks in advance.
First, a couple of suggestions:
if (!elecFence) {
fencePole = [[Fence alloc] initFence:onFencePole
fenceType:1 fencePos:currentTapLoc];
}
else {
fencePole = [[Fence alloc] initFence:onFencePole
fenceType:2 fencePos:currentTapLoc];
}
You’re making this too hard, how about this:
const int fenceType = elecFence ? 2 : 1;
Fence *fencePole = [[Fence alloc] initFence:onFencePole
fenceType:fenceType fencePos:currentTapLoc];
And this:
int xMax = [fencePoleArray count];
int yMax = [fenceImageArray count];
for (int x = 0; x < xMax; x++) {
[[fencePoleImageArray objectAtIndex:x] removeFromSuperview];
}
for (int y = 0; y < yMax; y++) {
[[fenceImageArray objectAtIndex:y] removeFromSuperview];
}
Could be shortened using makeObjectsPerformSelector:
const SEL remove = #selector(removeFromSuperview);
[fencePoleImageArray makeObjectsPerformSelector:remove];
[fenceImageArray makeObjectsPerformSelector:remove];
This is shorter and safer, as the xMax bound in your code is computed from fencePoleArray and used to iterate over fencePoleImageArray. (Could be right, could be wrong.)
Now to the objectAtIndex: call. If the array is still in memory and you tried to access an object beyond the array bounds, you would get an exception. So that I guess that either the array or some of the objects in it got released without you knowing it. You could try to NSLog the array and the object on given index and try to log their retainCount. If the logging line crashes, you have found the object that’s been released and can start looking for the cause.
(And one more thing: You should split the game logic into a separate model class. This simplifies the code and makes it easier to reason about.)
If you want to use properties, you should use self.propertyName = ... instead of propertyName = ....
Hope this will help.