Pointers, NSMutableArray, Retain, Loops and Confusion - iphone

It might be that the problem is straight forward but I don't get my head around it.
I have the following iPhone code
for(int x = 0 ; x < [allFriends count] ; x++)
{
Friend *f = [[Friend alloc] init];
f = [allFriends objectAtIndex:x];
if([uid isEqualToString:[f uid]])
{
[f AddAlbum:album];
[allFriends replaceObjectAtIndex:x withObject:f];
}
}
It doesn't matter where I call [f release] the app always crashes. Why? (BTW the loop runs a few thousand times)
Is there a more efficient way to do it?
I think I provided enough code, let me know if not!
Thanks heaps for your help!

The object you create in this line (and are presumably trying to release):
Friend *f = [[Friend alloc] init];
is immediately leaked when you then assign f to the object you get out of your array:
f = [allFriends objectAtIndex:x];
So it's really that object you're releasing, meaning that the pointer in the array is no longer valid (it's pointing at a released instance).

I think your code has some serious problems:
Why are you allocating a new Friend if you're going to immediately leak it?
Why replace an object in an array with the same object?
I think you can replace your code with this loop:
for (Friend *f in allFriends)
{
if([uid isEqualToString:[f uid]])
{
[f AddAlbum:album];
}
}

Seems like you're doing way more work than you need. Something like this (I think) does the same thing, but without the leaks or crashes:
for (Friend* f in allFriends) {
if ([uid isEqualToString:[f uid]]) {
[f addAlbum:album];
}
}

Related

NSMutableArray addObject freezes my app

Tons of similar questions, but none of their answers seem to answer mine...
I'm creating my array as such:
imgArray = [NSMutableArray arrayWithCapacity:10];
Later (in another function) I am trying to add an object to it:
Attachment newAttachment = [[[Attachment alloc] init] autorelease];
newAttachment.fileName = filename;
newAttachment.file = file;
[imgArray addObject:newAttachment];
This results in the iPhone app freezing up. The simulator seems fine; the clock on the status bar keeps ticking, I don't get any error messages, but my app is no longer responding.
What am I doing wrong?
It seems you are not retaining imgArray. Are you? Try,
imgArray = [[NSMutableArray alloc] initWithCapacity:10]
if not.
just do
imgArray = [[NSMutableArray arrayWithCapacity:10] retain];
all class methods if return an object is returned with retain count 1 and object already in autorelease pool so if want to use that object beyond the current working block the you should always retain that object because then reference is lost outside the block.

Pass variable by reference to method (Objective-C Iphone SDK)

Hi :) This is messing me up quite the bit...
Say I have this method:
-(void) initEvent:(NSMutableArray*) Day day:(float)DayNum
{
//[Day addObject:[[[LifeEvent alloc] init] initVars:100]];
[Day addObject:#"Hello"];
[Day addObject:#"there :)"];
}
I call that method in a small loop:
for (int i = 0; i < 7; i++)
{
NSMutableArray * DayTMP = [[NSMutableArray alloc] init];
[self initEvent:DayTMP day:i];
}
Theoretically, this should pass DayTMP to the function, and add data to that variable. Not the case, instead, it creates a copy of DayTMP, adds data to that value, and drops it. DayTMP never gets modified!
I need to know how to pass values to functions as pointers, not copies, so that DayTMP is modified.
Actually what you are doing here is that you are creating 7 NSMutableArray type objects and the same variable name DayTMP is used for all of them ....... so loose the access of all 6 of them and and you only can access the last one because in every itteration of the loop DayTMP is pointing to new location ....... so to achieve what you want you should do following...
NSMutableArray * DayTMP = [[NSMutableArray alloc] init];
for (int i = 0; i < 7; i++)
{
[self initEvent:DayTMP day:i];
}
Normally your code should work fine except that you never release DayTMP creating a memory leak. You are indeed passing a pointer to an NSMutableArray : (NSMutableArray*).
You "init" DayTMP inside the loop!!!
that means you create (and never release!) the same object many time, overriding it every time, so you kill the old one each time, and you get just the last one: it's a memory error

EXC_BAD_ACCESS in iPhone app - memory management issue

For reference, I've already read:
memory management question -- releasing an object which has to be returned
iPhone: Return NSMutableArray in method while still releasing
Releasing objects returned by method
Which I thought would help :).
This app is a teaching tool and is intended to help people visualize simple genetics. Just some background so the variable names and stuff will make sense. Here's the main code that executes when the app runs:
- (void)viewDidAppear:(BOOL)animated {
ThingzCore *core = [[ThingzCore alloc] init];
ThingzThing *thing1 = [[ThingzThing alloc] init];
thing1.breed = #"AB";
thing1.pattern = #"AC";
thing1.color = #"CA";
thing1.gender = #"XY";
thing1.generation = 1;
thing1.isEgg = NO;
ThingzThing *thing2 = [[ThingzThing alloc] init];
thing2.breed = #"CD";
thing2.pattern = #"BA";
thing2.color = #"CB";
thing2.gender = #"XX";
thing2.generation = 1;
thing2.isEgg = NO;
NSLog(#"Breeding GD BR PT CL G");
ThingzThing *child = [core mateFather:thing1 withMother:thing2];
NSLog(#"Round 1: %# %# %# %# %d",child.gender,child.breed,child.pattern,child.color,child.generation);
sleep(10);
child = [core mateFather:thing1 withMother:thing2];
NSLog(#"Round 2: %# %# %# %# %d",child.gender,child.breed,child.pattern,child.color,child.generation);
sleep(10);
child = [core mateFather:thing1 withMother:thing2];
NSLog(#"Round 3: %# %# %# %# %d",child.gender,child.breed,child.pattern,child.color,child.generation);
sleep(10);
child = [core mateFather:thing1 withMother:thing2];
NSLog(#"Round 4: %# %# %# %# %d",child.gender,child.breed,child.pattern,child.color,child.generation);
sleep(10);
[thing1 release];
[thing2 release];
[core release];
}
And here's what happens when I run it in various ways:
Running without breakpoints, it crashes, with no console message, after the 2nd sleep() but before the "Round 3" NSLog.
Running with breakpoints enabled, but none defined, it runs through the entire sequence. After the fourth sleep(), it crashes with EXC_BAD_ACCESS.
Running with breakpoints enabled and NSZombiesEnabled, it does the same thing as above - no further information, just EXC_BAD_ACCESS.
Running in Instruments, no leaks are shown.
This is the routine being called four times:
-(ThingzThing *)mateFather:(ThingzThing *)father
withMother:(ThingzThing *)mother {
// will we be doing a mutation?
int mutationPercentage = father.generation + mother.generation;
int mutationNumber = (arc4random() % ((unsigned)100 + 1));
BOOL isMutation = NO;
if (mutationNumber <= mutationPercentage) {
isMutation = YES;
}
// get possibilities
NSArray *possibilities = [self possibilitiesByMatingFather:father
withMother:mother
mutations:isMutation];
// randomly select one of the possibilities
int keeping = (arc4random() % ((unsigned)[possibilities count]));
return [possibilities objectAtIndex:keeping];
}
Without pasting in the ENTIRE code, the possibilitiesByMatingFather:withMother:mutations function is returning an NSMutableArray. That routine declares the array by using:
NSMutableArray *possibilities = [NSMutableArray array];
It then:
return possibilities;
It does not send a release or autorelease message to possibilities; my understanding is that creating the array the way I have is an implicit autorelease. I didn't want to alloc the array, because I'm returning it, so wouldn't have the opportunity to explicitly release it.
The objects held in the possibilities NSMutableArray are of a custom class. They are added as follows:
ThingzThing *newThing = [[ThingzThing alloc] init];
newThing.breed = choiceBreed;
newThing.gender = choiceGender;
newThing.color = choiceColor;
newThing.pattern = choicePattern;
newThing.generation = mother.generation + father.generation;
newThing.name = #"";
newThing.isEgg = YES;
[possibilities addObject:newThing];
[newThing release];
Which seems to work most of the time. At least, when breakpoints are enabled, the program runs through the code without complaint until the end, as noted above.
Any suggestions on what I'm doing wrong, here? It's obviously memory management issues of some kind, but I can't sort it in my head.
BTW, in a vain, throwing-things-at-the-wall attempt to figure it out, I did modify the one line from the main routine as follows:
// get possibilities
NSArray *possibilities = [[self possibilitiesByMatingFather:father
withMother:mother
mutations:isMutation] retain];
To no avail. Same results. So the problem isn't in retaining the array returned by possibilitiesByMatingFather:withMother:mutations. Forcing a retain on that return isn't helping.
Frequently in this type of situation, the actual error is not at the location shown in the debugger when the app halts.
For example, the debugger may be pointing to a method call, but the problem actually occurs inside the method -- not when the method is called.
To track things down, I would suggest setting a breakpoint just before the method call that triggers the error -- in your case, this would be the mateFather: withMother: call. Then step into that method. There is a good chance you will find that the problem happens inside that method -- or even inside a method called from within that method.
Check you have the correct property declarations of the string properties of class ThingzThing.
e.g.
#property (nonatomic, retain) NSString* breed;
NEED to be retain or copy NOT assign...
Found it. Buried eight method calls down, I was sending release to an NSArray that was obviously autoreleasing. When the initial calling routine (viewDidAppear) fell down into autorelease mode, it tried to autorelease the already-released object, and exploded. Good grief - is there any way XCode could have helped me track that down?
In any event, in case anyone runs across this, make bloody sure you're not sending a release message to something that you didn't explicitly alloc yourself. If you didn't alloc it, odds are it was autoreleasing itself, and you sending a release to it takes the retain count negative, and the Foundation framework vomits with an EXC_BAD_ACCESS.

EXC_BAD_ACCESS Error for no conceivable reason

OK, This is a method from my program that keeps giving the EXC_BAD_ACCESS error and crashing. I indicated the line below. questionsShown is a readwrite property and points to an NSMutableArray that I initialize with a capacity of 99 at an earlier point in the program. When I debug everything appears normal in terms of the property being allocated. I assumed there must be some issue with memory management but I am having serious trouble finding the problem. Thanks in advance for any help.
#synthesize questionList;
#synthesize questionLabel;
#synthesize questionsShown;
-(IBAction)next{
int numElements = [questionList count];
int r;
if (myCount == numElements){
[questionLabel setText:#"You have seen all the questions, click next again to continue anyways."];
[questionsShown release];
questionsShown = [[NSMutableArray alloc] initWithCapacity:99];
myCount = 0;
}
else {
do {
r = rand() % numElements;
} while ([questionsShown indexOfObjectIdenticalTo:r] != NSNotFound);
NSString *myString = [questionList objectAtIndex:(NSUInteger)r];
[questionLabel setText:myString];
myCount++;
[questionsShown addObject:r]; //results in crash with message EXC_BAD_ACCESS
myCount++;
}
}
The EXC_BAD_ACCESS is coming from dereferencing r, which is just an integer. Your compiler should be giving you a warning (make pointer from integer without a cast) on that line.
If questionsShown is supposed to be some kind of index set for you (which it appears to be), you might want to either use that class, or you will have to box your integer in an NSNumber object. So:
[questionsShown addObject:[NSNumber numberWithInt:r]];
and when you read it:
[questionsShown indexOfObjectIdenticalTo:[NSNumber numberWithInt:r]]
I recommend, however, that you take a look at the NSIndexSet documentation.
With a mutable index set, you could do:
[questionsShownIndexSet containsIndex:r]
and
[questionsShownIndexSet addIndex:r]

Objective-C iPhone - NSMutableArray addobject becomes immediately out of scope

ok. I have a really odd and mind boggling problem. I have two class files, both of which are NSObject inheritors. The series of code is as follows
CustomClass *obj;
obj = [[CustomClass alloc] init];
[myArray addObject:obj]; <--------Immediately after this line if I hover over the array it shows it as having 1 object that is out of scope.
If I hover over both objects they both have what look to be initialized memory locations so I really have no idea what is going on here. Thanks in advance.
UPDATE: There is a place in the code where I call a function repeatedly with a timer. Inside of the timer I do the following.
CustomClass *obj = [CustomClass alloc];
obj = [myArray objectAtIndex:0];
obj.var += 10;
[obj release];
On the line obj.var I get a EXC_BAD_ACCESS error. I am probably doing the alloc and releases incorrectly considering it is called repeatedly but I have tried everything I can think of.
I think you are referring to the XCode debugging feature which shows you the content of variables.
I did encounter the same issue as well, and what I'm sure of is that this is generally not a problem with your code.
Now what I'm not sure of is why this happens, but I believe that the variable obj in your example is not used after the call anymore. This means the compiler reuses the place where this reference was stored, thus the debugger could "lose" the pointer to your variable and it will appear as out of scope (but I am no expert in the ways of gcc or the debugger, so I could be wrong here).
This code is wrong:
CustomClass *obj = [CustomClass alloc];
obj = [myArray objectAtIndex:0];
obj.var += 10; [obj release];
What you are doing is allocing a new CustomClass (without initializing it, which should never be done), then replacing it with the object from the array (leaking the old one), and then afterwards releasing the object from the array. This will cause a crash the next time the object in the array is accessed. Instead, just say:
CustomClass *obj = [myArray objectAtIndex:0];
obj.var += 10;
Don't release unless you retain in advance. (See the Cocoa memory management guide for more information).
This isn't the problem you are referring to, but please don't do this:
CustomClass *obj = [CustomClass alloc];
Never issue an alloc without an init of some sort. Also, in the context of the code you posted it isn't required, as you assign a value to obj on the next line.
Then [obj release]; isn't required, as you haven't retained the obj value you obtain from myArray. You are probably doing it because of the preceding alloc, which as I have said isn't required.
if a reference to obj.var is causing a BAD_ACCESS, then either obj or var has been dealloced by code elsewhere, almost certainly var.