Deleting an Object after collision - objective-c

I am making a game, and part of the game is a rabbit collecting eggs. I am having an issue with when the rabbit intersects the egg the game is crashing. the error I am getting is Collection <__NSArrayM: 0x17805eed0> was mutated while being enumerated.'
I have an image of 1 egg, and the egg appears after every couple of seconds, when the rabbit intersects the egg, I just want the egg to disappear and give 1 point.
Here is the code I am using
In the header file I have
#property (strong, nonatomic) NSMutableArray *eggs;
and the implementation file I have this for adding the egg
UIImageView *egg = [[UIImageView alloc] initWithFrame:CGRectMake(CGRectGetWidth([[self gameView] frame]), holeBottom - 115 , 50, 60)];
[egg setImage:[UIImage imageNamed:#"easterEgg.png"]];
[[self gameView] insertSubview:egg belowSubview:[self counterLabel]];
[[self eggs] addObject:egg];
And this for detecting collision and trying to remove the egg
for (UIView *egg in [self eggs]) {
[egg setFrame:CGRectOffset([egg frame], [link duration]*FBSidewaysVelocity, 0)];
if ( CGRectIntersectsRect (rabbit.frame, CGRectInset ([egg frame], 8, 8))) {
[[self eggs]removeLastObject];
[self incrementCount];
}
}
I'm hoping you can see where I have gone wrong with this code and help me to rectify the problem.
Thank you in advance for your time

the error message if very clear that you cannot mutable collection (e.g. remove element) while enumerating it (e.g. using for in loop)
the easiest solution is to copy the collection and enumerate the copied one
for (UIView *egg in [[self eggs] copy]) { // <-- copy
// you can modify `[self eggs]` here
}
or
NSMutableArray *tobeRemoved = [NSMutableArray array];
for (UIView *egg in [self eggs]) {
if (condition)
[tobeRemoved addObject:egg];
}
[[self eggs] removeObjectsInArray:tobeRemoved];

Collection <__NSArrayM: 0x17805eed0> was mutated while being enumerated is being caused because you are looping over an array, while at the same time deleting the objects in that array. There are a few ways to get around this, one way is to create a new array of the objects that you want to delete while looping over the original array eggs and after the loop is finished, looping over this new array and performing the remove.
Code example:
NSMutableArray *eggs;//this is full of delicious eggs
//...
NSMutableArray *badEggs = [NSMutableArray array];//eggs that you want to removed will go in here
for(NSObject *egg in [self eggs]){
if([egg shouldBeRemoved]){//some logic here
[badEggs addObject:egg];//add the egg to be removed
}
}
//now we have the eggs to be removed...
for(NSObject *badEggs in [self badEggs]){
[eggs removeObject:badEgg];//do the actual removal...
}
note: your line of code [[self eggs]removeLastObject]; looks like a mistake in any case... this removes the object at the end of the array (I don't think you want to do this...)

Related

NSMutableArray objectatindex always shows the last Object

my problem is that my NSMutableArray always get the last element with the objectatindex-method.
I have an array with some classes derived from UIViewController. I want to show one View after another.
first i fill the array:
ContactViewController *ContactView = [[ContactViewController alloc]init];
QuestionViewController *QuesView = [[QuestionViewController alloc]init];;
ContactView.mydelegate = self;
[QuesView setDelegate:self];
[Views addObject:ContactView];
Views =[[NSMutableArray alloc]initWithCapacity:11];
for (int i = 0; i < 11; i++) {
[QuesView setParam:#"text" :i ];
[Views addObject:QuesView];
}
after that i want to get the actual view and jump to the next like that:
-(IBAction)Button:(id)sender
{
UIViewController *newView = [[UIViewController alloc]init];
newView = (UIViewController*)[Views objectAtIndex:enumerator];
[self presentViewController:newView animated:YES completion: nil];
enumerator++;
//dismiss old view here....
NSLog(#"number %d",[newView getNumber]);
}
the new view is not shown and the number in the log is always the last number of the array. I tried to go with a for loop through all element in "Views" but there is always the last number in every object....
any hints?
You probably want to create multiple QuestionViewController instances. But you actually create only one object and call setParam on it 11 times.
Also this line [Views addObject:ContactView] has no effect, because you create a new array object and assign it to Views in the next line. The same thing with UIViewController *newView = [[UIViewController alloc]init]. Hope you are using ARC, otherwise this would create a memory leak!

Remove all items from UITabBarController

I'd like to remove all items from UITabBarController within MainWindow. I can achieve it this way:
self.tabViewController.viewControllers = [NSArray array];
self.tabViewController.customizableViewControllers = [NSArray array];
But what about old controllers that was there? Is this more correct way?
- (void)cleanCurrentTabbar {
for (id ctrl in self.tabViewController.customizableViewControllers) {
[ctrl release];
}
for (id ctrl in self.tabViewController.viewControllers) {
[ctrl release];
}
self.tabViewController.viewControllers = [NSArray array];
self.tabViewController.customizableViewControllers = [NSArray array];
}
Your second option is more correct concept wise as well with respect to memory management because it releases all allocated resources before making it nil.
But rather than giving it an empty array which is in itself an autoreleased object like [NSArray array], you can assign nil.
- (void)cleanCurrentTabbar {
for (id ctrl in self.tabViewController.customizableViewControllers) {
[ctrl release];
}
for (id ctrl in self.tabViewController.viewControllers) {
[ctrl release];
}
self.tabViewController.viewControllers = nil;
self.tabViewController.customizableViewControllers = nil;
}
Also as James Webster has said in blow comment:
"You may or may not need to release depending on the type of property viewControllers and customizableViewControllers are"
Hope this helps you.
That's cleaner in terms of memory yes. You should release objects when you are finished with them, that includes before reassigning.
However, I notice you are using self.tabViewController.viewControllers. Is that property assign or retain? If it's retain, the release will be done internally.
As #Parth Bhatt told, releasing viewControllers items looks like good idea. Maybe. But in my case it leads to the strange EXC_BAD_ACCESS errors:
So I end up with self.tabViewController.viewControllers = nil; and its works just fine.

Memory leaks while using NSMutableArray

Hi guys can somebody please advise how to cure the memory leaks in the code below
i've tried just about every combination of release and autorelease i can think of but every time either the app crashes or the leak remains
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
//get refereance to the textfield
UITextField *currentTextField = (UITextField*)[self.view viewWithTag:200];
//check which picker
if(pickerView.tag ==1)
{
// Only calls the following code if component "0" has changed.
if (component == 0) {
// Sets the global integer "component0Row" to the currently selected row of component "0"
component0Row = row;
// Loads the new values for the selector into a new array in order to reload the data.
newValues = [[NSMutableArray alloc] initWithArray:[pickerData objectForKey:[selectorKeys objectAtIndex:component0Row]]];
currentValues = newValues;
// Reloads the data of component "1".
[pickerView reloadComponent:1];
}
//run the selector logic
[self textFieldDidEndEditing:currentTextField];
}
hope someone can advise
many thanks
Your problem is these two lines:
newValues = [[NSMutableArray alloc] initWithArray:[pickerData objectForKey:[selectorKeys objectAtIndex:component0Row]]];
currentValues = newValues;
The first line allocated a new instance of NSMutableArray. The second line copies the pointer from newValues to currentValues, overwriting the pointer value in currentValues. Whatever currentValues was pointing to is lost. That's the leak.
You could fix it like this:
newValues = [[NSMutableArray alloc] init...
[currentValues release];
currentValues = newValues;
This way, whatever was pointed to by currentValues has its reference count decremented before you lose access to it.
You could also solve the problem by making currentValues an Objective-C property, and using the accessor methods via self.currentValues or [self setCurrentValues:]; those methods will handle retain/release for you.
Your NSMutableArray allocation is never released.
newValues = [[NSMutableArray alloc] initWithArray:[pickerData objectForKey:[selectorKeys objectAtIndex:component0Row]]];
You should autorelease that or release it later on when you know you don't need it anymore.
Not sure how you have currentValues defined, but this should work without leaks:
In your .h file:
#property (nonatomic, retain) NSArray * currentValues;
In your .m file:
#synthesize currentValues;
self.currentValues = newValues;

How to manage memory/usage of a NSMutableArray of NSMutableArrays

I am currently trying to write a class to create faux grid system to keep track of a NSMutableArray of game entities using a NSMutableArray of NSMutableArrays. Given my limited experience with Objective-C programming, I am unsure of how certain things work.
Here is the init method:
#define MAX_BALL_ROWCOUNT 6
#define MAX_BALL_COLCOUNT 4
- (id) initWithMutableArray:(NSMutableArray *)aList {
self = [super init];
if (self != nil) {
ballList = [[NSMutableArray alloc] initWithCapacity: MAX_BALL_ROWCOUNT];
for (int i=0; i<MAX_BALL_ROWCOUNT; i++) {
NSMutableArray *balls = [[NSMutableArray alloc] initWithCapacity:MAX_BALL_COLCOUNT];
[ballList addObject:balls];
[balls release];
}
int x = 0;
for (NSMutableArray *array in ballList) {
for (int i = 0; i<MAX_BALL_COLCOUNT; i++) {
[array addObject:[aList objectAtIndex:x]];
x++;
}
}
}
return self;
}
ballList is the class's NSMutableArray that will store NSMutableArrays.
aList is the NSMutableArray containing the GameEntities I wish to keep track of that is passed into this class.
All the sizes and amount of entities to store are fixed, which is why there is no checks on the sizes of the arrays nor the number of entities to store.
So the first question I have involves freeing memory. This is the dealloc function I currently have:
- (void) dealloc {
[ballList release];
[super dealloc];
}
Does calling a release on ballList cause the release to be called on the NSMutableArrays that it contains (which will subsequently call the release on the objects those NSMutableArrays contain) or do I have to write something like:
for (NSMutableArray *array in ballList) {
[array release];
}
[ballList release];
My second question involves the usage of this array of arrays. Is this the proper way to traverse through ballList?
- (void) update {
for (NSMutableArray *array in ballList) {
for (GameEntity *balls in array) {
(CGPoint) location = [balls getLocation];
[balls setLocation: CGPointMake(location.x+1, location.y+1)];
}
}
}
Lastly, in the code above where it sets the balls location, does it only affect the contents within ballList or does the original aList that is passed into ballList change as well? If the contents in the original aList do not change, how would I write it so that they do?
If people have suggestions for a better way to keep track of the entities in a grid system, I'd be open to those too. Thanks in advance.
First : One release is enough for the NSMutableArray instance to release all it's object.
[ballList release];
Second : Your code for updating GameEntity instance is fine and will also effect to the original aList (which you called) .
When the dealloc of a NSArray or NSMutableArray is called, all its contents gets a release message. So when you release ballList, if there there is no other owner (I guess in this case there is none) then its dealloc is called and you don't need to release the other arrays here.
Your loop traversal is fine. Though for 2D arrays instead of NSArray of NSArray I personally prefer pure C 2D array, at least in most of the cases.
When you are adding object in this way you are adding a reference in the array. So any change via the array's reference will be reflected in all references of the object. If you don't want that then add a copy of the object in the array.

Add NSMutableArray to another NSMutableArray

Hey! I've been trying to add an array to an NSMutableArray using the addObject syntax. The app crashes without any explicit mention of an error. Could you please tell me how this is done?
I have a class Stack that creates an array. So I call that class using an instance called tem that I have created. Hence, [self tem] is my call to the array. Through the program I merely add UILabels to the array(I know you'd suggest adding a string and then changing to UILabels, but I need to do it this way) and towards the end, I'd like to add this array to my 'list' array.
-(Stack *)tem {
if(!tem)
tem=[[Stack alloc]init];
return tem;
}
-(void)viewDidLoad{
//code
list=[NSMutableArray arrayWithArray:[self list].array];
}
-(IBAction)opPr:(UIButton *)sender
{
if([[[sender titleLabel]text] compare: #"="]==0) {
//code
UILabel *t=[[UILabel alloc]init];
//complete creating label
[[self tem]push:t];
//add above label to tem array
[list addObject:[self tem].array];
[table reloadData];
}
}
OK, this answer got all cluttered with edits. I've edited it to be more clear, at the possible expense of understanding the thread of how we arrived at the final answer.
The final answer
The answer was to change:
list=[NSMutableArray arrayWithArray:[self list].array];
To:
list = [[NSMutableArray alloc] init];
(...Which isn't really the best way to create an NSMutableArray, but it may work anyway.)
This was based on an erroneous version of the asker's code
Based on your comment that it crashes after [list addObject:[self tem].array];, I must conclude that your instance variable list is of type Stack*, and that Stack is not a subclass of NSMutableArray. If so, that's your issue.
In that case, changing that line to [[list array] addObject:[self tem].array]; should fix it.
This is just good advice
As an aside, NSMutable array is perfectly capable of acting as a stack without modification. Example:
NSMutableArray* ar = [NSMutableArray arrayWithCapacity:someCapacity];
// Push
[ar addObject:narf]; // narf being some object reference
// Pop
id popped = [ar lastObject];
[ar removeLastObject];
If you want to encapsulate stack behavior in a semantically consistent way, you can add push and pop methods to NSMutableArray using a category. This would make your code simpler and less prone to error.
This was my first stab at answering the question, before any code had been posted
This is a stab in the dark since you've not posted any code. BUT. One way to accomplish that with arrays is by creating arrays using [NSArray arrayWithObjects:obj obj ... nil] and omitting the nil terminator on the list of objects. Are you by any chance doing that?