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.
Related
This question already has answers here:
When to use -retainCount?
(11 answers)
Closed 9 years ago.
I have following code:
- (IBAction)HeyCount:(UIButton *)sender {
NSString* strr = [[NSString alloc] initWithString:#"hi there"];
self.string = #"789";
ohYeah = #"456";
NSLog(#"Retain Count of ohYeah:[%d] with String:[%ld]",[ohYeah retainCount],(long)[ohYeah integerValue]);
NSLog(#"Retain Count of strr:[%d] with String:[%ld]",[strr retainCount],(long)[strr integerValue]);
}
And the out put of the above code is:
Retain Count of ohYeah:[-1] with String:[456]
Retain Count of strr:[-1] with String:[0]
Declaration of ohYeah is in .h file
NSString * ohYeah;
I'm not using ARC. Can anyone of you explain why retain count of both strings is -1 and accessing an object with retain count -1 should not be crash?
I guess the compiler is clever and creates string literals from your given code. Since those reside in their own memory space and are never released they get a retain count of UINT_MAX. UINT_MAX printed with %d will result in -1. Use %u for unsigned integers.
You shouldn't look to closely at retainCount.
There are objects like constant strings that don't take part in the retain/release mechanism. For example, #"456" is such a constant string. You can release or retain it as much as you like, nothing will happen.
There are other objects like #123 that are not even objects in a 64 bit system. They behave like objects, but no memory is ever allocated for them.
In both cases, the retain count won't give any sensible result. Which is why it is very, very rare that you should ever look at the retain count.
And then there are methods like "copy" which sometimes copy an object, sometimes just retain the original object. So if you have an object with a retain count of 100, and you make a copy, that copy might have a retain count of 1 or 101.
Note that retainCount is declared like this in NSObject.h:
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;
You should use %u to display it on 32 bits architecture and %lu on 64 bits.
But you shouldn't use directly retainCount, use it in your code means that you've a problem of architecture, objective-c (ARC or Manual Reference Counting) give a complete set of mechanism to manage memory and objects life cycle properly.
I am playing with objective-c and did sample test.
In non-arc environment I have the following code:
NSNumber * one;
NSLog(#"At first one retain count is: %d",[one retainCount]);
one = [[NSNumber alloc]initWithInt:5];
NSNumber * two = [[NSNumber alloc]initWithInt:1];
NSNumber * three =[[NSNumber alloc]initWithInt:2];
NSLog(#"After initializing %d",[one retainCount]);
NSMutableArray * array = [NSMutableArray arrayWithObjects:one,two,three, nil];
NSLog(#"After adding to array it is: %d",[one retainCount]);
NSString * a = [array objectAtIndex:0];
NSLog(#"Assigning to variable a: %d",[one retainCount]);
NSLog(#" %# ",a);
[one release];
[array removeObjectAtIndex:0];
NSLog(#"after releasing and removing from array %d",[one retainCount]);
NSLog(#" %# ",a);
It seems like the I wouldn't be able to use nslog the variable a but I can do it.
I am getting the following output;
2013-03-07 17:57:09.706 Interview[33491:11303] At first one retain count is: 3
2013-03-07 17:57:09.707 Interview[33491:11303] After initializing 2
2013-03-07 17:57:09.707 Interview[33491:11303] After adding to array it is: 3
2013-03-07 17:57:09.707 Interview[33491:11303] Assigning to variable a: 3
2013-03-07 17:57:09.707 Interview[33491:11303] 5
2013-03-07 17:57:09.707 Interview[33491:11303] after releasing and removing from array 1
2013-03-07 17:57:09.708 Interview[33491:11303] 5
How it's possible that I can still use the variable a even if I it supposed be deallacated?
You'll get told many times you should not use retainCount, but your question is:
How it's possible that I can still use the variable a even if I it supposed be deallacated?
When an object is deallocated that simply means that the memory that was used for it is added to the pool of available memory. The memory previously in use is not completely overwritten to remove all traces of what was stored in it.
Furthermore when you invoke [one release] this only indicates you no longer have an interest in the object referenced by the value stored in one (and as a result that object's memory may be returned to the free pool) it does not alter the value stored in one itself. So after the call one still contains the reference to where the object was, or still is...
If you wish to make sure you don't use an out-of-date reference you can use code like:
[one release]; one = nil;
Finally you report that before you even allocate your object your first NSLog outputs:
2013-03-07 17:57:09.706 Interview[33491:11303] At first one retain count is: 3
How can you have a retain count of 3 when you've never even allocated an object? The answer is you are lucky your code didn't blow up; when a local variable, which your one appears to be, is created it starts with garbage contents - calling a method using that garbage as an object reference is unwise. Remember Objective-C is not a "safe" language and will not protect you from such errors. Note that instance and global variables are initialised to 0/nil, and invoking methods on nil is supported in Objective-C - you just get 0 back.
Because you can never be fully sure that your object hasn't been retained elsewhere in the framework. Be sure you obey the memory management policy, and let the framework worry about its obligations.
Additionally, don't use retainCount. Apple tells you explicitly not to use it, and it isn't guaranteed to tell the truth.
Directly from the documentation: Do not use this method.
Special Considerations
This method is of no value in debugging memory management issues. Because any number of framework objects may have retained an object in order to hold references to it, while at the same time autorelease pools may be holding any number of deferred releases on an object, it is very unlikely that you can get useful information from this method.
To understand the fundamental rules of memory management that you must abide by, read “Memory Management Policy”. To diagnose memory management problems, use a suitable tool:
The Clang Static analyzer can typically find memory management problems even before you run your program.
The Object Alloc instrument in the Instruments application (see Instruments User Guide) can track object allocation and destruction.
Look here, this explains everything more clearly:
http://www.whentouseretaincount.com
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.
When I create an object and check its retain count, I get 1 as expected. When I release the object and then check the retain count again, it is still 1. Shouldn't the object be deallocated, and the retain count 0?
NSMutableString *str=[[NSMutableString alloc] initWithString:#"hello"];
NSLog(#"reference count is %i",[str retainCount]);
[str release];
NSLog(#"reference count is %i",[str retainCount]);
I do see 0 for the retain count if I set str to nil first. Why is that?
Don't use retainCount, it doesn't do what you expect in most cases.
Your second NSLog is accessing deallocated memory as an object. In this particular case, that deallocated memory still contains enough of the old data from the NSString that was just freed for the program to not crash when the retainCount method is called on it. Had you run this with NSZombieEnabled you would have gotten an error message about sending a message to a deallocated instance.
The reason it returns 0 when called for nil is that methods returning integers will always return 0 when called on a nil object.
Do not depend on retainCount. And do not care about this. Lots of things may happen under the hood. You only need to ensure that you have released all the things that you owned. If you are trying to be sure that you are not leaking any memory, then use Instrument, not retainCount in NSLog.
Can someone explain why the last line prints out -1? It happens when copy is called on a NSMutableString, I expect the returnCount of strFour to be 1, since an immutable copy should be returned.
NSMutableString *str =[NSMutableString stringWithString:#"hi"];
NSLog(#"new instantiated variable has a retain cout:");
NSLog(#"%d",[str retainCount]); //1, str is a pointer, its value is a memory address
NSMutableString *strFour =[str copy]; //receiver str is mutable, copy returns an immutable
NSLog(#"%d",[strFour retainCount]); ////strFour s retain count should be 1, but it had a retain count of -1
Thanks a lot.
Never bother looking at the retain count of an object. It is always meaningless to do so. The retain count is likely affected by optimisations “under the hood”. These optimisations rely on the fact that your code follows the Cocoa Memory Management Guidelines. Just worry about sticking to those guidelines and don't bother looking directly at the retain count.
One reason why it could be (-1) because the string “hi” may be cached somewhere and your copy is referring to the cached string. Keep in mind that the retain count is actually an unsigned integer. The documentation dor -retainCount says that for objects that never get released, the retain count should be UINT_MAX (which when printed as a signed decimal will come out as “-1”).