retain count in iphone - iphone

I have used [anArray retainCount] to get the retain count of array..(i know this should not be used but i am using just for learning retain concept)
Following is my code.
NSString *str = [[NSString alloc] initWithFormat:#"a,b,c,d"];
NSArray *anArray =[[NSArray alloc]init];
NSLog(#"Retain count: %i", [anArray retainCount]);
anArray=[str componentsSeparatedByString:#","];
NSLog(#"Retain count: %i", [anArray retainCount]);
output
Retain count: 2
Retain count: 1
i think it should be opposite but....

Please do yourself a favor and don't look at retainCount trying to learn how the memory management rules work. Instead refer to the friendly Apple Memory Management Guide.
In your examples:
NSArray *anArray =[[NSArray alloc]init];
You have allocated "anArray" (by calling alloc), so you are responsible for calling release.
anArray=[str componentsSeparatedByString:#","];
Now, you have obtained a new object (leaking the original, as seand said). This time, you do not own the object (because componentsSeparatedByString does not have alloc or copy in its name), so you must not release it.
Don't worry about what the retainCount is; tend to your own knitting and release objects that you should and don't release objects you don't own.

This line...
anArray=[str componentsSeparatedByString:#","];
You squished the original assignment of 'anArray' (thus creating a leak).
In real life, you'd want to [anArray release] first.
That's why the retain count went back to 1.

The documentation states that the retain count is unlikely to provide any useful information. It is NOT a good way to learn about retain and release concepts.

Related

Understanding memory management in ios

I am in the process of learnig objective-c and programming an iPad app. One thing I keep tripping myself up on and having to re-read is memory management. I am getting there...slowly. Basic rules such as for every alloc / retain you must have a release is useful. However, one relatively basic thing eludes me and I wonder if someone could explain...
Take the following code...
NSArray *myArray = [[NSArray alloc] init];
myArray = [someNSSet allObjects];
This is relatively straight forward coding and would require a [myArray release] statement.
However, I keep seeing examples of (and indeed, I have used extensively the following 'short cut'...
NSArray *myArray = (NSArray *)[someNSSet allObjects];
How, as far as I understand when you use the (NSString *) you dont need to use a [myArray release] statement, but I dont understand why.
Could someone possible explain?
NSArray *myArray = [[NSArray alloc] init];
myArray = [someNSSet allObjects];
this code is leaking myArray because you lose the reference to NSArray that you've allocated on the first line; you don't need to alloc here, because on the second line you're assigning a new value to myArray.
NSArray *myArray = (NSArray *)[someNSSet allObjects];
and this code example is perfectly fine, you're assigning the result of [someNSSet allObjects] to myArray pointer and you don't own the returned value, so you don't need to care about releasing it.
Consider using ARC (Automatic Retain Counting) for you project. With ARC the compiler takes care of retain counts so you don't have to, in fact aren't allowed to. There is a refactoring that will convert a current project.
As you said, there is a leak in the first code you posted. so you must add a release:
NSArray *myArray = [[NSArray alloc] init];
[myArray release];
myArray = [someNSSet allObjects];
In fact, when you obtain an object through a method that starts with alloc, new or copy, you own it, and you should release it. That's why, here you should release the array you obtained using the method alloc. This convention makes it easy to know when you own objects and when you don't. So remember: alloc, new or copy.
As for the second example, you obtained the array though a method that doesn't start with one of the three words (alloc, new or copy), so you don't own the object, and you are not responsible of releasing it. In fact, the array you obtained is an autoreleased object, which means that even though its retain count is currently 1, it will be automatically released when something called the autorelease pool is drained.
Here is a reference about Memory Management Rules.
In the first line:
NSArray *myArray = [[NSArray alloc] init]
some amount of memory is allocated for an array (actually in this case it is senseless since the size of the array is 0. Keep in mind that NSArray is immutable!).
The variable myArray holds the address of the first byte of the reserved memory area.
Now in the second line you change the value of myArray which now will point to the first byte of the memory area where [someNSSet allObjects] is stored. At this moment you do not know any more where the array is stored what you've created in the first line. And so you have a leak.
The line:
NSArray *myArray = (NSArray *)[someNSSet allObjects];
is correct, since you do not reserve any memory at this point. If you are not using ARC you might call retain in order to keep GC away from the referenced block of memory. In other way you might receive a BAD_EXEC when the owner of the object releases it and you try to access it through e.g.: [myArray objectAtIndex:0]

iPhone memory management with NSString problem

#property (nonatomic,copy) NSString *orginalString;
..
NSString *tmpString =[[NSString alloc] init];
self.orginalString=tmpString;
[tmpString release];
NSString *newString =self.orginalString;
What happens here to newString?, is this correct what I am doing?
orginalString retain count 1 at first, and when it is referenced with another pointer "newString" its retain count will be 2? do I need to say "self.orginalString=nil" in the end? there are serious memory leaks but dont know it is something related with this.
NSString *tmpString =[[NSString alloc] init];
tmpString is allocated and initialized
self.orginalString=tmpString;
the string pointed to by tmpString is copied over to self.originalString (because the property is declared copy);
[tmpString release];
the string pointed to by tmpString is released, correctly; nothing happens to the string pointed to by self.orginalString;
NSString *newString =self.orginalString;
a new pointer is created and initalized to point at the same string pointed to by self.orginalString; nothing happens to self.orginalString retain count; it's just a second pointer pointing to the same object;
at this point, if you don't release somewhere self.orginalString, it will be leaked.
When you are dealing with memory management in OBjective C, my suggestion is not try and reason in terms of "retain count"; retain count is just the mechanism that is used by the ObjC runtime to keep track of objects; it is too low-level and there are too many other objects around to increase or decrease the retain count, so that you immediately loose count.
The best way, IMO, is reasoning in terms of ownership: when an object wants ownership of another, it will send a retain; when it has done with it, it sends release. Ownership is a local concept to a class, so it is easy to track down.
So, when you do:
NSString *newString =self.orginalString;
newString is just a pointer to a not-owned object; you do not need to balance that assignment with a release; on the contrary, if you do:
NSString *newString = [self.orginalString retain];
you are making yourself responsible for releasing the object when you have done with it.
You should visit this link. Actually, we should not check memory leaks with retain count, atleast for NSString.
To check memory leaks, always use Instruments coming with Xcode.

What is the right way to get an NSString object from an NSArray, keeping Memory Managment in mind?

What is the right way to get an NSString object from an NSArray, keeping Memory Managment in mind.
Suppose I have an array
NSArray *myNewArray = [[NSArray alloc] initWithObjects:.......];
Now I want to get an object from this NSArray at index 2.
NSString *nameString = [myNewArray objectAtIndex:2]; // is it the right way? how to deal with "nameString"
// now regarding memory managment, should I release it ?
OR I should first alloc nameString and then assign value to it ?
Check out the Cocoa Memory Management rules (how many times have I started a post with that sentence?). In particular
You only release or autorelease objects you own.
You take ownership of an object if you create it using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message.
You use release or autorelease to relinquish ownership of an object. autorelease just means “send a release message in the future” (specifically: when the used autorelease pool receives a drain message—to understand when this will be, see “Autorelease Pools”).
Does the method objectAtIndex: begin with "alloc"? No. Does it begin with "new"? No. Does it begin with "copy" or "mutableCopy"? No. Have you sent retain to the returned object? No.
Therefore you do not own nameString. Therefore you must not release or auto release it.
Sorry if the above seems a bit "leading by the nose" but when I first started with Objective-C, I found it useful to pretty much go through all the above in my head in exactly that way, otherwise I tended to get it wrong. It doesn't take long for it all to become second nature.
I think you don't totally get the "pointer" concept yet. Your variable nameString is just a pointer. Not a string.
In the line :
NSString *nameString = [myNewArray objectAtIndex:2];
You just assign the pointer to the actual memory address of the second object of the array. That's all.
If you are about to keep this object alive (even if the array will be deallocted), you better retain that object.
NSArray *myNewArray = [[NSArray alloc] initWithObjects:.......];
NSString *nameString = [myNewArray objectAtIndex:2]
[myArray release];
That's it, no need to bother any more with it. NSString will be released by environment itself.
There is no need to allocate or initialize NSString object and after all if you are not allocating any memory then there is no need to release....Only release NSArray objects nothing else....
You are going through right way...
There is no need to release the nameString.You only release when you are using(alloc”, “new”, “copy”, or “mutableCopy”) .
NSArray *myNewArray = [[NSArray alloc] initWithObjects:.......];
and getting value in NSString from any of index wont affect memory ...no need to allocate here.
The collected NSString need not required to be retained until you are passing its ownership to another controller/object.

retain Count NSArray vs. NSMutableArray

Short Question with a code example:
NSLog(#"%i", [[[NSArray alloc] init] retainCount]);
NSLog(#"%i", [[[NSMutableArray alloc] init] retainCount]);
Output:
2
1
Why is the retainCount from the NSArray and NSMutableArray different?
Nobody outside of apple knows for sure (but I'm sure soon there will be somebody that claims he knows exactly why that happened).
Maybe this happens because iOS is smart and it reuses empty NSArrays. And obviously [[NSArray alloc] init] creates an empty array that is of no real use. And since it`s not mutable (ie you can't add objects later, and it will be empty forever) all empty NSArrays pointers can reference the same object.
The mutable one can't be reused because you can add objects to it.
Do not use retainCount!
From the apple documentation:
Important: This method is typically 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 Rules”. To diagnose memory management problems, use a suitable tool:
The LLVM/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.
Shark (see Shark User Guide) also profiles memory allocations (amongst numerous other aspects of your program).
The reason is that [[NSArray alloc] init] returns the same object no matter how many times you call it. Look at this code:
NSArray *array1 = [[NSArray alloc] init];
NSArray *array2 = [[NSArray alloc] init];
NSArray *array3 = [[NSArray alloc] init];
NSLog(#"\narray1: %p\narray2: %p\narray3: %p",
array1, array2, array3);
The output is:
array1: 0x10010cae0
array2: 0x10010cae0
array3: 0x10010cae0
This makes sense, because NSArray is immutable, and all empty arrays are identical. It looks like NSArray keeps an empty array handy for this purpose since the retain count for the array pointed to by array1, array2, and array3 is 4.
I don't disagree with #fluchtpunkt's answer, but I think it's safe to say that we know exactly why this happens. I suppose you could say that nobody knows exactly why Apple chose to implement it this way, but it does seem like a good idea.

Objective C NSMutableString* property retain count oddity

if I create an nsmutablestring and then release it , shouldn't the retain count be 0?
my retain count stays 1.
NSMutableString *text = [[NSMutableString alloc]init];
[text release];
NSLog(#"retain count %d ", [text retainCount]);
Am I missing something ?
thanks.
There's no guarantee that retainCount will return the correct value at any point during the object's lifecycle. If you've created an NSMutableString using [[NSMutableString alloc] init] and you're calling release on it once, you're doing the right thing and shouldn't worry about it.
Apple says in its documentation that retainCount is of no use for memory management purposes because the frameworks and autorelease pools can keep hold of an object even if you have released it. http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/retainCount
Since you're doing this for debugging purposes, I'd suggest that you use categories to add some test code to an existing class. Any time you manually retain or release your object, you could call your new methods and use that to track your memory usage.