Will the retain count increase when added to an array? - objective-c

I just wanted to know: will the retain count of an object be incremented if it is added to an array or dictionary in Objective-C? Can I release a particular object immediately after adding it to an array or dictionary?

Yes, it will increase the retain count of the object you added, that is why you can release the object immediately after adding it to the array.
NSObject obj1;
obj1=[[NSObject alloc] init];
//obj1's retain count is 1 here.
[array1 addobject:obj1];
//obj1's retain count incremented by 1, so the total retain count is 2.
[obj1 release];
//obj1's retain count decremented by 1, so the total retain count is 1.
array1 will keep the object until the array1 itself is not released.

Hariprasad,
NS[collection name here] retain objects added to them as NSResponder noted. A few other facts:
To your comment "can I release it
after adding", the short answer is
yes. Often times I do an
autorelease for objects that are
bound for containment in a
collection and won't be needed outside the collection.
When you remove an
object from a collection, the
reference count is decremented. If
you want to ensure it won't be
deleted from memory (next pool
sweep) you need to retain the
object.

NSArrays retain any object added to them.

Related

iOS memory management - clarifications

I know that alloc and retain will increase the reference count of an object. Is there any other different method that actually increment the reference count? And when/how does dealloc is called?
alloc allocates an object with retain count 1.
Methods that start with new also return an object with retain count 1.
retain increments the count by 1.
release and autorelease (at the end of the run loop) decrement it by 1.
Methods that start with the name of the class (without prefix) return an autoreleased object, meaning that it will be released at the end of the cycle, if you don't retain it yourself.
Finally, methods that copy an object (usually start with copy) also create a copy with retain count 1.
dealloc is called when the retain count of an object drops to 0.
PS. In case you didn't know about it yet, consider using Automatic Reference Counting (ARC).
With these the retain count gets increased.
new, however it can be seen as alloc+init.
retain
copy creates new object with retain count=1
mutableCopy creates new object with retain count=1
dealloc is called automatically as soon as retain count reaches to 0.

Does removing an object from NSArray automatically release its memory?

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
myClass *obj = [[myClass alloc] init];
NSArray *ar = [NSArray array];
[ar addObject: obj];
[ar removeObject: obj];
[pool drain];
Will removing an object from an NSArray array automatically release its memory that I have earlier allocated?? The answer seems to be yes from what I have found from various sources. The problem is if I test for memory leaks, xcode still complains that obj has not been released. So what's actually going on?
Collections retain the objects you add to them, claiming temporary ownership. When you remove an item from the collection, it releases the object (and its temporary claim). In other words, the retain count will be the same before you add an object to a collection and after you remove it.
If that retain count is 0, the memory is reclaimed.
In your code you're allocating an object and claiming ownership of it. That means it has a retain count of 1.
Then you're adding it to the array. The array retains the object, taking temporary ownership and upping its retain count to 2.
You then remove the object from the array. The array releases the object and relinquishes any claim of ownership, bringing the retain count back down to 1.
Since memory is not reclaimed until retain count is back to 0 (nobody has a claim on the object), your object's memory is not reclaimed.
If you had autoreleased the object prior to adding it to the array, or called release on the object after you had removed it (but not both!), the retain count would be 0 and the memory would be reclaimed.
Yes. When you insert an object into an array, the array retains it (bumps its retain count). If the object's retain count is 1 (ie, there are no other retains on it) then when it's removed from the array the retain count goes to zero and it's eligible to be deleted.
But your problem in the above scenario is that, after adding the object to the array, you failed to release YOUR retain on the object (due to the alloc/init). Insert [obj release] after the [ar addObject:obj].
(Also note that in your example the entire array will go "poof" when you drain your autorelease pool.)
No, you alloc it -> retain count of 1
You add it to the array which sends the object another retain -> 2
You remove the object from the array and the array sends a release -> 1
...so now the retain count is back to 1, which is your initial alloc retain, so you need to release it to free the memory.

Question about NSMutableArray, pointers and release

How exactly does the addObject method of NSMutableArray work? Does it create a new instance and add it into the array or does it simply add a reference to the SAME object into the array?
If the answer is it only insert a reference to the object, then it leads to my next question:
Let's say I have the following method in one of my class ('list' is a NSMutableArray), gladly, this code works the way I wanted, but i just don't seem to fully understand why:
-(void)buyItem:(Item *)anItem
{
Item * newItem = [[Item alloc]init];
newItem.name = anItem.name;
newItem.details = anItem.details;
[list addObject:newItem];
[newItem release];
}
So basically after calling [list addObject:newItem], there would now be total of two reference pointing to the same object right(newItem, and another one in the 'list' array)?
But why does releasing the newItem object here, doesn't wipe out the one in the 'list' NSMutableArray? Aren't they pointing to the same Object?
When you are adding object to NSMutableArray using method addObject: it retains added object. This is why you can release it later and use afterwards by accessing using objectAtIndex: method.
It adds a reference and then increases the objects retain count by one. What you are doing is correct and it will still exist in the array with a retain count of one.
For your reference.
What increases an object's retain count?
It's important to understand the distinction between release and dealloc. release simply decrements the "retain count", except that when the count is decremented to zero, release goes on to dealloc the object.
In general (except where documented otherwise), when you pass an object reference (ie, pointer) to an Objective-C object, and it keeps a copy of that reference beyond the duration of your call to it, it retains the object on its own behalf, and it takes the responsibility to release the object when it is itself deallocated, or when the copy of the reference is nullified or overwritten.

what's the difference between two code scenario

Scenario1:
NSDictionary *dictionary =
[[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.stateZips = dictionary;
[dictionary release];
Scenario2:
self.stateZips = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
dependes on stateZips property.
If it is retained:
Scenario 1: stateZips is properly retained ( a release on stateZips will call its dealloc). also local dictionary is released then and there.
Scenario 2: stateZips is retained twice ( a release in stateZips will not call its dealloc as it is still retained).
If it is assigned:
Scenario 1: stateZips points to released dictionary and accessing it else where might result in crash.
Scenario 2: stateZips is properly retained ( a release on stateZips will call its dealloc).
copy is not being considered, as i believe its not your intention (at least in this piece of code)
Both cause self.stateZips to be set to a dictionary initialized with the file pointed to in plistPath.
But in the second, the pointer to the initialized dictionary was not saved, and as it's an object with a retain count of +1 technically a release message needs to be sent to it in some place, to balance the memory management. But as there is no way to retrieve the pointer to that object, you'll end up with a memory leak.
Two exceptions apply:
1.Garbage Collection
If you're in a garbage collected environment, both are the same. Well, they are not the same, but the result is similar.
2.Property type
If the setter for stateZips simply assigns the pointer, then you can release the object using the ivar pointer. Then these two pieces of code have only one difference: in the former, the object is released right after it's used. In the latter, it's just "undefined". Without the context, it's hard to determine if this object was released or not, and when.
I am assuming that stateZips is a property with the retain attribute.
In Scenario 1. A dictionary is created with a retain count of 1 in the first line. In the second line the property will call retain again, increasing the retain count to 2. Finally the retain count is decremented by the release. This will leave the dictionary with the correct retain count.
In Scenario 2, the retain is only called once.
The net effect of the two scenarios is the same. The dictionary object will be retained, and you will need to include a release in the dealloc method of the class.
If this were not correctly handled by the compiler, it would be very hard indeed following the retain/release rules of objective-c.

Retain count in objective C return -1

I'm new to objective C, I have a NSMutableArray with 3 objects in it, then I try to print the retainCount of the array. Why the final retainCount return -1? Thanks
NSLog(#"myArray has retain count of %d", [myArray retainCount]);
[myArray release];
NSLog(#"myArray has retain count of %d", [myArray retainCount]);
Result from console:
2010-10-17 11:58:06.407 TestRetainCount [527:a0f] myArray has retain count of 1
2010-10-17 11:58:06.407 TestRetainCount [527:a0f] myArray has retain count of -1
After an object has been deallocated (which may happen after a release), you can no longer rely on its data being intact. You're trying to trust the retain count after it has become invalid.
On a general note, don't use the retain count. Ever. Use the rules in the memory management programming guide, and you'll always get the reference counting correct.
Graham Lee answered the question specific to your example.
not specific to your example, but to your question (subject):
UINT_MAX is often used to denote an object which uses no reference counting (e.g., is never deallocated, such as a singleton), or a custom reference counting implementation.
Can't rely on an accurate retainCount because of the timing autoreleased objects. That said, count your alloc/init, new, retains, etc... and match with corresponding release.