Can anybody explain why the retain count of this line of code:
[[[SomeClass alloc] init] retain]
Is two? I'm only calling retain once.
Because alloc adds 1 to the retain count. You should read Apple's Memory Management Programming Guide.
The retain count is two because [alloc] also increases the retain count. Strictly speaking the retain count of an object isn't just how many times you've called retain, but how many things are holding on to it.
If you create an object, using a method who's name begins with alloc, new, copy or mutableCopy, or you retain an object, its retain count is increased by 1
If you release or autorelease an object, it's retain count decreases by 1
In your example code, both alloc and retain increase the retain count by 1.
See Apple's docs for further details:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
Related
My knowledge of ARC has been tested today, i stumbled on this article and it has an example under the heading "Nesting of statements" which in my mind seems wrong.
In the example they show embedded above, the line highlighted with a green underline says that the string alloced inside the function would first get a retain count +1 when being created, then +1 again when adding to the array, then once the array is nil'ed after the for loop, the retain count of the string would be reduced by 1, leaving the original string with a retain count of 1, thus not being dealloced.
I would have assumed the compiler would have been smart enough to at least make an object like that not actually have a retain count initially, since if you just had
[[NSString alloc] initWithFormat:#"Name 1"]];
this string being alloced would have nothing pointing to it and would be released when the autorelease pool comes to an end instead of having a retain count of 1 forever. so why would it have different behaviour when its in a parameter of a function? (unless that line does have a retain count of 1 and this is somehow a memory leak? otherwise it could have a retain count of 1 till the end of its scope at most surely, but then that logic would apply if its a parameter as well i would assume)
Is this article wrong or is my understanding of ARC flawed?
The article is wrong.
Your understanding is essentially correct, though the autorelease pool is not used in this case. The sub-expression:
[[NSString alloc] initWithFormat:#"Name 1"]];
returns an owned object, as do all init methods. That object is passed to addObject: and the array also takes ownership. After that ARC sees the string is no longer required by the method and relinquishes its ownership - leaving the array as the only owner.
HTH
ARC is not flawed here. Sounds like the article is wrong.
ARC will release the allocated parameter object as expected while the array keeps its reference. Once the array is released, the object will have no more references and it will also be deallocated, as expected.
I have an instant variable "obj1" in MyClass.h.
#property (nonatomic, retain) NSMutableArray *arrObj1;
and in MyClass.m viewDidLoad method, i have allocated another object "obj2" and assign that to obj1.
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *arrObj2 = [[NSMutableArray alloc] initWithObjects:#"a",#"b",#"c", nil];
NSLog(#"arrObj2 count %lu",(unsigned long)[arrObj2 retainCount]);
self.arrObj1 = arrObj2;
NSLog(#"arrObj1 count %lu",(unsigned long)[self.arrObj1 retainCount]);
NSLog(#"arrObj2 count %lu",(unsigned long)[arrObj2 retainCount]);
}
Here is the output
2015-08-19 11:06:14.461 MyClass[1812:24133] arrObj2 count 1
2015-08-19 11:06:16.332 MyClass[1812:24133] arrObj1 count 2
2015-08-19 11:06:17.327 MyClass[1812:24133] arrObj2 count 2
I am not getting how arrObj2 get retain Count value 2.
please explain me.
Thank you
A more relevant question to your problem is: Why do arrObj and arrObj2 seem to share properties? And the answer is they're two references to the same object. That means the same array is referenced strongly in the same place; that is, arrObj1 and arrObj2 are actually the same array. That's why you see a retainCount of 2, though you shouldn't use retainCount for this. (More on that later.) Compare the addresses of the arrays in the debugger instead; they will be the same. If you add an object to one array, it'll be added to "the other."
You can fix that by using copy on the property declaration instead, or by changing self.arrObj1 = arrObj2 to self.arrObj1 = [arrObj2 mutableCopy] . (Edit: I'm not actually sure changing the property type to copy will help here, since it's a mutable type. It would work if it was just an NSArray, though.)
I hope that answers your question, but now I want to explain why it's the wrong question. Please don't take any offence, because learning this is important and not easy. :)
Think in terms of relationship type, not retain/release
You shouldn't be thinking in terms of retain counts at all, but in terms of strong and weak relationship: A strong relationship expresses an ownership interest in the object, a weak relationship doesn't and will be converted to nil shortly after all ownership interests in the object are removed. Also, note that the retain property type is deprecated: it should be strong in ARC code.
Don't use retainCount.
Don't use retainCount. Or, if you prefer, When to use Retain Count:
Never.
Then there's Apple's official documentation, which begins:
This method is of no value in debugging memory management issues.
Or there's this from bbum, which I consider even better. He goes into great detail about why retainCount is useless, concluding with:
Bottom line: the only time the absolute retainCount can be conclusively used for analytic purposes is if you have the backtrace of every retain and release that contributed to the current retain count’s value (there is another use case, documented at the end). If you have that, then you don’t need the retain count and, fortunately, Instruments is already generally quite adept at producing a per-object inventory of retains and releases for you.
Basically, it's value is not useful. It will return (in some cases) the number of times an object has been retained without releasing. It does not (and can not) take the number of times it has been autoreleased into account. And it will not always return the "correct" value even without considering autorelease, since some objects can never be deallocated from RAM.
in Objective-C an object is a reference type.
The retain count is increased the first time when the object was allocated.
When the object is assigned to arrObj1 the object is not copied when the property is declared as retain or strong so arrObj1 and arrObj2 contain the pointer to the same object. The implicit setter of the property arrObj1 increases the retain counter a second time.
Memory management is the programming discipline of managing the life cycles of objects and freeing them when they are no longer needed.
Managing object memory is a matter of performance; if an application doesn’t free unneeded objects, its memory footprint grows and performance suffers.
Memory management in a Cocoa application that doesn’t use garbage collection is based on a reference counting model. When you create or copy an object, its retain count is 1.
Thereafter other objects may express an ownership interest in your object, which increments its retain count.
The owners of an object may also relinquish their ownership interest in it, which decrements the retain count. When the retain count becomes zero, the object is deallocated (destroyed).
Check this image.
https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/Art/memory_management.jpg
Hope this help.
After the statement
self.arrObj1 = arrObj2;
the variable arrObj2 and the property self.arrObj1 point to the very same object.
If they point to the same object, and arrObj2 has a reference count of 2, what reference count do you expect self.arrObj1 to have?
Reason why retain count is coming as 2 is because you have used retain for NSMutableArray *arrObj1, so in effect
when you allocate arrObj2 retain count become 1,
the when you assign it to arrObj1 as its having a retain property, count increase - becoming 2.
arrObj2 is same arrObj1 as you have not copied it (as Steven Fisher in above answer pointed out) both has same retain count.
If you make arrObj1 to assign property then count will be remained as 1.
Simply put, the object pointed to by arrObj2 is the same object pointed to by arrObj1. Instruments shows us that this object gets +1 retain count when you called initWithObjects:
And that it got +2 retain count when you called setArrObj1 (i.e. you used the self.arrObj1 = ... syntax):
For demonstrations using Instruments' "Allocations" tool for tracking memory usage, see WWDC 2013 video Fixing Memory Issues and WWDC 2012 video iOS App Performance: Memory. Bottom line, while it will take some practice to efficiently find the correct objects in the "Allocations" tool, this "Record reference counts" feature is invaluable in finding where the strong references to the objects in question were established.
I'm sure you've seen it, but I'd also refer you to the Advanced Memory Management Programming Guide.
When you alloc a new memory area (I call it M) and assign it to obj2, the retainCount of M is 1.
When you do: self.obj1 = obj2.
Because self.obj1 is a retain property, so M will be retain +1, so its retainCount = 2 now.
Cause obj1 & obj2 are references to M, so their retainCount are 2.
Let try [obj1 release] and get retainCount of obj2 again to check.
Hope it helps.
Its very common question everybody familiar with, but I'm still not understand it fully.
If Object A owns (have a strong property of) Object B, and Object B have a strong property of object A, there is retain cycle, and no object can be released and there is a memory leak.
But, what if Object A instead will point for Object C instead of Object B, therefore another address in memory?
As far as i know, strong properties do something like follow:
- (void)setObject:(id)newObject{
if (_newObject == newObject){
return; //
}
NSObject *oldObject = _newObject;
_newObject = [newObject retain];
[oldObject release];
}
So, what if we point instead for Object C, isn't in that case memory for Object B will be released? What if both Objects (A and B) will instead set nil object? Is there still would be retain cycle with memory leak? With old value "floating" somewhere in memory?
I know, that has been discussed many times, but i still can't get "whole picture" in my head. I would appreciate any clarification in that matter.
The word you are looking for is "retain cycle".
The simplest retain cycle would be an object having a strong reference to itself. Very rare because it is rather pointless.
The most common case is A having a strong reference to B and B having a strong reference to A. A->B->A. You see the cycle?
The cycle can be any length A->B->C->D->E->F->G->...->A. It's a retain cycle, so nothing will be released. If you have just A->B->C->D->...->Z with no reference back to another object in the sequence, then there is no cycle. No cycle, no problem.
If the question is "can you break a retain cycle by reassigning one of the properties?", the answer is yes. This applies equally if you assign nil to the property.
As far as I know, creating an NSMutableArray with a helper method such as arrayWithArray adds both the array and the mutable array to the current autorelease pool. With mutableCopy, the array being copied as added to the autorelease pool but the resulting NSMutableArray does not. Without ARC, it's a notable difference.
But when using ARC, is there any difference beyond what is described above and which is irrelevant with ARC? I've seen code using both ways. Is there an established best practice on how to create mutable versions of immutable objects, when ARC is turned on, and why is it so?
Since arrayWitharray add two object in current autorelease pool, but latter does not. So that performance of first one is slightly less due to the draining of autorelease pool. So use the latter one below. The simple and best way to convert immutable array to mutable array in arc or non arc:-
NSMutableArray *array=[yourArray
mutableCopy];
I want to print retain count of NSString in AppDelegate class in didFinishLaunchingWithOptions method
NSString *str = [[NSString alloc] init];
NSLog(#"str retain count %d",[str retainCount]);
but it always gives -1 instead of +1....why ???
NSUIntegerMax means the returned object is immortal. This used to be in the docs, but has since been removed (because -retainCount is very discouraged).
In MRC, some people would actually override -retainCount to prevent their singletons from ever being deallocated.
In this case, it is a logical optimization for [[NSString alloc] init] to return a constant/immortal, rather than creating an empty string for each request. Of course, you should not rely on this detail/behavior in your program.
Apple docs say:
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.
So you shouldn't count on its correctness.
Also, -1 is actually largest unsigned integer, not negative value. Retain count returns NSUInteger, so you should use %u instead of %d.
Generally you should no longer use the -retainCount method, as pointed out by others' answers. The reason is, a lot of retain/release work is done inside the NSString class depending on how you create it. When you create an NSString you could actually be creating one of many NSString subclasses (the id return type of the initialisers is not specific).
All NSConstantStrings (those created by #"") are not releasable - they exist for the duration of the program (as specified by both gcc and clang). Thus, Apple have arbitrarily set its retainCount to be the highest possible unsigned integer (or -1 if it is read as signed, as it is here) because it makes no sense for a constant object, alive for the duration of the program, to have a retain count.
When you create an empty string in the way you have, it is likely Apple just automatically point you to the constant #"" in memory as it takes up less space at runtime. As your object is now an NSConstantString, it is implemented to return a retain count of -1.
EDIT: Incidentally, as NSConstantString is a subclass of NSString it must implement the methods that NSString implements, including -retainCount. This is why you can actually call the -retainCount method on a constant string object (and why Apple make it return a special value). This inheritance relationship can be found near the bottom of the NSString.h header.