views:

674

answers:

6

I declare my array in my *.h file:

@interface aViewController: UIViewController
{
   NSMutableArray *anArray;    // You will need to later change this many times.
}
@end

I alloc memory for it my *.m file:

-(void) viewDidLoad
{
   anArray = [[NSMutableArray alloc] init];
}

I click a test-button to load my array (eventually it will need to load DIFFERNT values on each click):

   anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];

And I free it here:

-(void) dealloc
{
   [anArray release];
   [super dealloc];
}

Does that all look ok?

Because it crashes when I later run this code:

   NSLog(@"%d", [anArray count]);

Not sure why a simple "NSLog() and count" would crash everything.

+5  A: 

You are not loading your array with

anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];

Instead, you are replacing it with a new instance, and worse: with an instance, whose reference is actually owned by some entity you do not control (most likely, an NSAutoreleasePool.) The reference you properly owned, the one created by

[[NSMutableArray alloc] init]

is lost and will be leaked.

Instead of replacing the entire array reference, mutate the one you have at your disposal already, using for example addObject: like

[anArray addObject: @"one"]
[anArray addObject: @"two"]

etc. In order to clear out old values, the method removeAllObject may be handy. There are also mutation methods, which may be used to add multiple values at once.

Alternatively, you can allocate the array using the construction method you already use, but be careful to retain it. In viewDidLoad do

anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain];

instead of the alloc/init sequence.

If you really intend to replace the entire array, you may want to consider using properties instead of doing the reference counting manually.

Dirk
+2  A: 

The problem is anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil]; This replaces the array you initially created. The problem with doing so is that this new array isn't retained, so you lose it as soon as the method returns. Further, you have a memory leak because you never freed the original array.

There are several ways to fix this, but one is to use [anArray release]; anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain]; instead.

Another, probably more correct way to fix it would be to use the addObject: or addObjectsFromArray: NSMutableArray methods instead of constantly creating new arrays.

David Kanarek
A: 

Wow. I REALLY have totally misunderstand everything about strings, arrays, and memory. I thought the "easy way" was to alloc ONCE... use the mutable array... change it as much as you want... and free it ONCE.

The problem with doing so is that this new array isn't retained,

I would think the old array would be gone... and the new array could be used. (But I guess not.)

Further, you have a memory leak because you never freed the original array.

I was thinking the old array wasn't suppose to be freed... I'm not done with it... I just wish to CHANGE it to contain my new values. (But I guess not.)

but one is to use [anArray release];

I was thinking that would cause me to release the memory I allocated... (but I guess not)... and then I'd have to re-alloc more memory. (But I guess not.)

anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain];

So I have to "retain" it... so it doesn't disappear out from under me? (Not sure why it would. Until I tell it to... in my final dealloc call.)

Another, probably more correct way to fix it would be to use the addObject: or addObjectsFromArray: NSMutableArray methods instead of constantly creating new arrays.

I only want to create ONE array... and just use it as I want to. I never want to ADD to the array. I want to set it to my new values.

Bonnie
The problem is that what you are changing is a pointer, not an object. So pointing to a new object means the old object is left floating inaccessible. I would read Apple's Memory Management Guide to learn why it is that some objects disappear on you: http://developer.apple.com/iPhone/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
David Kanarek
A: 

You are not loading your array with anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil]; Instead, you are replacing it with a new instance, and worse: with an instance, whose reference is actually owned by some entity you do not control

Wow. So I could have 20 arrays... all called the same name: anArray... and they would be all different? (There's no such thing as a GLOBAL array?)

etc. In order to clear out old values, the method removeAllObject may be handy. There are also mutation methods, which may be used to add multiple values at once.

So... first I have to "remove all the objects"... and then I can call ONE method it re-add all my new values.

anArray = [[NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil] retain]; instead of the alloc/init sequence.

Wow. I thought nothing could be stored in an array without alloc'ing space for it.

If you really intend to replace the entire array, you may want to consider using properties

How would I do that using properties?
What would be the correct way to do something like this:

> anArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];
> anArray = [NSMutableArray arrayWithObjects:@"four", @"five", @"six", nil];

Just like I would do:

x = 12;
x = 24;
Bonnie
Uhhh... I detect a serious misunderstanding here with respect to how `NSObject` references work in Objective-C... I do not want to sound condescending, but maybe you should invest a little more time in studying the basics of C and Objective-C and how pointers work, what object *references* are, and why they are distinct from the name of the variable you assign them to...
Dirk
A: 

Looks to me like this would be the easiest way to do this. (And it seems to work. But it is truly correct?)

Don't alloc any memory for my NSMutableArray initially.
Don't re-alloc any memory repeatedly.  (When I change my array's values.)
Don't release it repeatedly. (Before I change my array's values.)
Don't release it when I exit the program.

But:
Always remember to use RETAIN when I initially assign 
(and repeatedly reassign) new values to my anArray variable.
Bonnie
A: 

Dirk,

Let me put it this way: I have a HUGE misunderstanding of pointers, arrays, strings, and memory.

I've read everything I can find on it... but (yet) to find a simple, clear, easy-to-understand description.

Can you suggest one? (Hopefully less than 10 pages of reading.) Is there a reference that explains JUST this topic... and from a standpoint of "you have 12 years of coding experience... but NONE that ever dealt with allocating memory or pointers".)

So the variable-name is NOT the way I refer to the object? Then why have it?

I'm used to many other languages that just do this:

myString = "this"
myString = "that"

myInt = 5
myInt = 15

(What could be simpler.)

Bonnie