Logic issue in array indexing - ios

I've probably been starting at this too long and simply can't see the logic problem. I'm changing background images on a pan gesture. Swiping left/right cycles thru an array of image names for the background and loops.
Swiping Right (increasing) works fine, it loops back to the start of my array.
Swiping Left (decreasing stops at the first object in my array (objectIndex: 0).
NSLog(#"_imageBackgroundIndex Before:%d",_imageBackgroundIndex);
if ([_panDirection isEqual:#"Right"])
{
_imageBackgroundIndex = _imageBackgroundIndex + 1;
}
if ([_panDirection isEqual:#"Left"])
{
_imageBackgroundIndex = _imageBackgroundIndex - 1;
}
NSLog(#"_imageBackgroundIndex After:%d",_imageBackgroundIndex);
if (_imageBackgroundIndex > ([_backgroundImages count] - 1))
{
_imageBackgroundIndex = 0;
}
if (_imageBackgroundIndex < 0)
{
_imageBackgroundIndex = ([_backgroundImages count] - 1);
}
[[self childNodeWithName:kBackgroundName] runAction:
[SKAction setTexture:
[SKTexture textureWithImageNamed:
[_backgroundImages objectAtIndex:_imageBackgroundIndex]]]];
Anyone see the issue?

Code looks okay (though there are some style improvements to consider once you get it working). I'd wager that you have _imageBackgroundIndex declared as an unsigned int or NSUInteger. When you think it drops below zero, it's really taking on a huge unsigned value.
This code will work (and has better style) even if the counter is declared unsigned...
- (void)incrementIndex {
BOOL increment = self.imageBackgroundIndex < self.backgroundImages.count-1;
self.imageBackgroundIndex = (increment)? self.imageBackgroundIndex+1 : 0;
}
- (void)decrementIndex {
BOOL decrement = self.imageBackgroundIndex > 0;
self.imageBackgroundIndex = (decrement)? self.imageBackgroundIndex-1 : self.backgroundImages.count-1;
}
Then your pan method becomes simpler:
// not sure how panDirection is initialized, is it really a string #"Left" or #"Right"?
// if so, use isEqualToString to compare strings
if ([_panDirection isEqualToString:#"Right"]) [self incrementIndex];
else if ([_panDirection isEqualToString:#"Left"]) [self decrementIndex];
[[self childNodeWithName:kBackgroundName] runAction:// ... etc

Related

How to stop count after Position.x on node is past position.x on another node

At the moment once my object has gone past a node, the highscore continuously counts up.
I only wish for it to count up by 1 once its past.
-(void)increment
{
self.number ++;
self.text = [NSString stringWithFormat:#"%i", self.number];
NSLog (#"%i", self.number);
}
-(void)handlePoints
{
[world enumerateChildNodesWithName:#"obstacle" usingBlock:^(SKNode *node, BOOL *stop) {
if (node.position.x < hero.position.x) {
PMPointsLabel *pointsLabel = (PMPointsLabel *)[self childNodeWithName:#"pointsLabel"];
[pointsLabel increment];
}
}];
}
I only want it to count up by a single number, how can I change this? It will currently keep counting for every pixel it travels.
Your question is a little confusing, as it isn't clear if your goal is to only add the point once on the enumerateChildNodesWithName or only increment it once it passes it completely.
To do the former
-(void)handlePoints
{
[world enumerateChildNodesWithName:#"obstacle" usingBlock:^(SKNode *node, BOOL *stop) {
if (node.position.x < hero.position.x) {
PMPointsLabel *pointsLabel = (PMPointsLabel *)[self childNodeWithName:#"pointsLabel"];
[pointsLabel increment];
*stop = YES; // To be extra safe you can always test for stop being non-nil, but it should always be non-nil
}
}];
}
Setting *stop = YES will stop the enumeration.
If you want to stop it "forever" or until some other condition, you'll need to store additional state in the class to prevent it. You would need logic based on the condition either inside handlePoints or in the calling method of handlePoints to prevent either enumeration (in the case of it being in handlePoints or calling handlePoints if it is the calling method.

sorting through an array - objective C/iOS

so I'm creating a contact list app and I'm storing everything into an NSMutableArray. I've managed to get add function working perfectly. But I'm struggling with the Previous/Next functions.
I can get it to go back one object in the array when pressing previous, but i Can't get it to go back any further? here's my code: I have two extra classes, PhoneBookEntry which is a subclass of the Person class. These classes contain three strings, Firstname,lastname and studentID
- (IBAction)addPerson:(id)sender {
PhonebookEntry *person = [[PhonebookEntry alloc] init];
NSLog(#"%#",self.firstName.text);
person.firstName = self.firstName.text;
person.lastName = self.lastName.text;
person.phoneNumber = self.phoneNumber.text;
[self.entries addObject:person];
Here's my Previous button:
int length;
length = [self.entries count];
if (length > 0) {
int index;
index = [self.entries count] - 1;
NSLog (#"%d the index is", index);
NSLog(#"object %#", [self.entries objectAtIndex:index]);
} else {
NSLog (#"No contacts have been entered. No");
}
//NSLog(#"%d is the length - 1 hopefully", length);
//NSLog (#"index at %d is ", length);
I've tried removing the - 1 here:
index = [self.entries count] - 1;
and changing then on the next line putting index--; but nothing seems to work. it just goes back once.
I understand that length is getting the amount of objects in the index, and then -1 but shouldnt i-- at the end of the count / - 1 keep removing it everytime its pressed??
Any ideas? Cheers
You're going to keep hitting the same index with that piece of code - you need to store the state somewhere. Who is going to hold onto what the current index is? With a good designed system the model should really take care of this.
You are best off storing the current index into an ivar and updating that every time the button is pressed.
#interface OKAClass ()
#property (nonatomic, assign) NSInteger currentIndex;
#end
//... initialise the property with a default value
self.currentIndex = [self.entries count] - 1;
//... when the button is pressed decrement the index (you might want some min / max validation or use modulus to loop over and start from the top again)
NSLog(#"%#", self.entries[self.currentIndex--]);

using an array objective C / iOS

so I'm creating a contact list app and I'm storing everything into an NSMutableArray. I've managed to get add function working perfectly. But I'm struggling with the Previous/Next functions.
I can get it to go back one object in the array when pressing previous, but i Can't get it to go back any further? here's my code: I have two extra classes, PhoneBookEntry which is a subclass of the Person class. These classes contain three strings, Firstname,lastname and studentID
- (IBAction)addPerson:(id)sender {
PhonebookEntry *person = [[PhonebookEntry alloc] init];
NSLog(#"%#",self.firstName.text);
self.currentIndex++;
person.firstName = self.firstName.text;
person.lastName = self.lastName.text;
person.phoneNumber = self.phoneNumber.text;
[self.entries addObject:person];
NSLog(#"%#", self.entries);
[self arrayLength ];
I've created a property to hold the current index.
#property (nonatomic, assign) NSInteger currentIndex;
I've created a method which then -1 from the currentINdex;
self.currentIndex = [self.entries count] - 1;
heres my button previous.
- (IBAction)btnPrevious:(id)sender {
//[self prevObject];
int length;
length = [self.entries count];
if (length > 0) {
NSLog(#"%#", self.entries[self.currentIndex--]);
// NSLog(#"object %#", [self.entries objectAtIndex:index]);
}
else {
NSLog (#"No contacts have been entered. No");
}
I can get it to go back once, but when I press it a second time Iget the following error.
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
Theres definitely data in there as I get it to print whats in the array, it also prints when I press previous also. happens no matter how many times I press the add button.
thanks
Better:
Previous Index:
// in order to go back you need to make sure that you're not already
// on index 0 and that you've items to go back to
if([self.entries count] > 1 && self.currentIndex > 0) {
self.currentIndex--;
}
Next Index:
// in order to go forward you need to make sure that you're not already
// on the last element
if(self.currentIndex < ([self.entries count] - 1)) {
self.currentIndex++;
}
Some further explanation on the root cause of your problem:
The main problem is, that you use currentIndex--. This will use the old currentIndex (which is 2) before decreasing the value. If you want to use the decreased value in this statement, you have to apply the decreasing before, i.e. by writing --currentIndex instead.
--expression = pre-decrement operator
expression-- = post-decrement operator
The pre-decrement operator does decrease the value and return the decreased value while the post-decrement operator will decrease the value by 1 and return the initial value.
i think you are starting from end of list
self.currentIndex = [self.entries count] - 1;
if current index is # 1 and you have 2 items in array adding an other will give you error
try this
NSLog(#"%#", self.entries[self.currentIndex--]);
For Previous
- (IBAction)btnPrevious:(id)sender
{
if(self.currentIndex <= 0)
{
self.currentIndex = [self.entries count] - 1;
NSLog(#"%#", self.entries[self.currentIndex])
}
else
{
self.currentIndex --;
NSLog(#"%#", self.entries[self.currentIndex])
}
}
For Next
- (IBAction)btnNext:(id)sender
{
if(self.currentIndex >= [self.entries count] - 1)
{
self.currentIndex = 0;
NSLog(#"%#", self.entries[self.currentIndex])
}
else
{
self.currentIndex ++;
NSLog(#"%#", self.entries[self.currentIndex])
}
}
Hope this will working for you.

Memory leak using ARC being indicated in iOS simulator

Somehow I am seeing memory increase in my simulator (the running bar graph).
I have an object called MyObject which has nothing but an int. In some other class (say MyCar in MyCar.h) I have an array of MyObjects, e.g. MyObject* junk[8];
and a method to return a specific one by index:
-(MyObject*) getJunk:(int) index{
if(junk[index] == nil){
return nil;
}
return junk[index];
}
In another class called DataModel I have a MyCar *mycar;
in DataModel I call a method ask
-(void) ask{
if(mycar == nil){
return nil;
}
for(int i=0;i<8;i++){
if( [mycar getJunk:i] == nil){
continue;
}
}
}
I call [self ask] say 10,000 times each time. I am using ARC, but I notice each time the iOS memory bar goes up. So something is accumulating memory; I don't know what, I don't have any allocs. Yes, this happens even if I write such non useless code which does nothing with the junk[i] returned to data model.
I even tried
-(void) ask{
if(mycar == nil){
return nil;
}
for(int i=0;i<8;i++){
MyObject* temp_junk = [mycar getJunk:i];
if( temp_junk == nil){
continue;
}
temp_junk = nil;
}
}
If you are calling [self ask] 10000 times in a loop, like this:
for (int = 0; i < 10000; i++)
[self ask];
then you are accumulating autoreleased objects inside the loop - those objects will not be released until your loop ends and the main run loop flushes the autorelease pool. Try creating your own autorelease pool inside your loop, like this:
for (int i = 0 ; i < 10000; i++)
{
#autoreleasepool
{
[self ask];
}
}
That will create a new pool each time through the loop and flush it each time so those autoreleased objects will go away.

Why am I able to reuse CCActionInterval?

I'm building a simple 2D game in Cocos2d which involves having enemies cross the screen across different, predefined paths. The nextFrame method has the following code:
int indexCount = 0;
for (Enemy *e in enemies) {
if ([cocosGuy doesCollideWithRect: [e boundingBox]])
{
for (Enemy *e in enemies)
{
[self removeChild: e cleanup: YES];
}
[self startGame];
}
// ^ This code not relevant to the question
if ([e numberOfRunningActions] == 0)
{
[e setPosition: [[enemy_positions objectAtIndex:indexCount] CGPointValue]];
[e runAction: [beziers objectAtIndex: indexCount]];
}
++indexCount;
}
The code in the second if statement above is intended to take a CGPoint from the 'enemy_positions' array and a CCActionInterval from the 'beziers' array. It works - when an enemy completes its path, it is repositioned and the action reruns. But why doesn't this break after the action runs for the first time? Aren't CCActions supposed to be one time only?
I ask because I want to refactor the position and action into a single struct, and I want to make sure I know what's going on first. Am I misunderstanding the CCAction class?
Also, here is the current factory method for generating the 'beziers' array:
-(NSArray*) makeBeziers {
ccBezierConfig bezierconf1;
bezierconf1.controlPoint_1 = ccp(-200, 5);
bezierconf1.controlPoint_2 = ccp(300, 100);
bezierconf1.endPosition = ccp(1000,5);
ccBezierConfig bezierconf2;
bezierconf2.controlPoint_1 = ccp(-200, 5);
bezierconf2.controlPoint_2 = ccp(300, 100);
bezierconf2.endPosition = ccp(1000,5);
ccBezierConfig bezierconf3;
bezierconf3.controlPoint_1 = ccp(-200, 5);
bezierconf3.controlPoint_2 = ccp(300, 100);
bezierconf3.endPosition = ccp(1000,5);
NSArray *myarray;
myarray = [[NSArray arrayWithObjects: [CCBezierBy actionWithDuration:3 bezier: bezierconf1],
[CCBezierBy actionWithDuration:3 bezier: bezierconf2],
[CCBezierBy actionWithDuration:3 bezier: bezierconf3],
nil] retain];
return myarray;
}
This works "by accident". Actions are supposed to be one time only. After they've run, they will be released.
However since you store the actions in a separate array, those actions are retained. Therefore you can re-run them. This might work for some actions, other actions may show subtle issues, and some actions may not do anything, leak memory or crash immediately if you do so.
Re-using actions is generally considered bad practice, unless you know the code of each action and you have verified that reusing it doesn't do anything "bad".

Resources