views:

562

answers:

5

This is a beginner level question in which I'm curious if this is a valid use of a pointer in a statement such as:

 NSMutableDictionary *foo = [bar mutableCopy];

I get confused when that is valid versus when I'd need to do the following:

NSMutableDictionary *foo = [[NSMutableDictionary alloc] initWithCapacity:0];
foo = [bar mutableCopy];
// use foo
[foo release];

Are both valid? When to use one over the other?

+3  A: 

The first one is correct, the second leaks memory because you alloc twice (copy counts as one) and release only once.

Don't forget to release foo after you are done though

cobbal
Don't release it. mutableCopy returns an autoreleased object.
NilObject
from the documentation: The invoker of the method, however, is responsible for releasing the returned object.
cobbal
@NilObject: No, it doesn't. See http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmObjectOwnership.html#//apple_ref/doc/uid/20000043-BEHDEDDB
Adam Rosenfield
@NilObject: read the memory management guidelines again. -mutableCopy is a copy method.
Graham Lee
+7  A: 

You would never need to write the code in the second example. The [[NSMutableDictionary alloc] initWithCapacity:0] does nothing except leak memory.

In the second example, you create an NSMutableDictionary and assign it to foo. Then in the next line, you assign a copy of another NSMutableDictionary to foo, meaning that the original dictionary foo pointed to is now just floating off somewhere on the heap, unable to ever be freed.

You will need to release foo in either case, though, as laid out in the Objective-C memory management guidelines.

Chuck
Minor correction: the assignment AFTER that line is what leaks the memory. However, I agree with you that this code should never be written. :-)
Quinn Taylor
+1  A: 

The act of assignment overwrites the previous value held by that variable. For example:

x = 3
x = 4

The value held by x at the start of the second line is 3, but after the line of code executes, it is 4. The syntax:

int x = 0;

is really just shorthand for this:

int x;
x = 0;

Variables that are pointers are no different. Thus if the variable's first reference is simply to assign to it, you do not need to first initialize it, because whatever value you're initializing it with will simply be discarded.

NilObject
A: 

The first one is the right way to do it. Both copy and alloc will allocate memory to your variable. So using the second option will increase the retain count of your variable to 2.

lostInTransit
+7  A: 

Guessing at why you might be confused, I'd like to add an explanation of what the second code sample actually does (and why it's not necessary).

NSMutableDictionary *foo = [[NSMutableDictionary alloc] initWithCapacity:0];

I think you are getting confused by this line because this line is often described as "initializing foo". That's a bit misleading. There are technically 2 different entities being changed here -- the new NSMutableDictionary object is created and the "foo" variable is assigned its address.

The line actually creates a new NSMutableDictionary object on the heap (your application's dynamic memory area). I'll call this "Dictionary 1". So that this new "Dictionary 1" object on the heap can be found, its memory address is stored in "foo". "foo"s role is to act as an index, so we can find "Dictionary 1".

While we often say: "foo is a dictionary", that's because we are lazy -- the statement is technically wrong. Correctly: "there is a dictionary on the heap and foo stores its memory address so that we can find it and use it".

When you then run the line:

foo = [bar mutableCopy];

you are using the address in "bar" to find a different object (I'll call it "Dictionary 2") in the heap, and make yet another object ("Dictionary 3") on the heap with the same values. If you're keeping count, this is now 3 objects in existence.

After "Dictionary 3" is made, its memory address is then stored in the "foo" variable. This storing into "foo" overwrites the existing memory address (the one that pointed to "Dictionary 1"). This means that we have no remaining pointers to "Dictionary 1" and hence will never be able to find it again. This is why we say "Dictionary 1" has leaked.

I hope you can see from this situation why "Dictionary 1" was never needed (you only ever intended to use "foo" to access the copy, "Dictionary 3").

Matt Gallagher