Objective C NSMutableString* property retain count oddity - iphone

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.

Related

objective-c: when to autorelease an nsnumber object when not using alloc

I noticed that my program was crashing because it was running out of memory. I figured out that this was happening because of this code segment:
DataSet *tempSet = [[DataSet alloc] init];
tempSet.rightFoot = [NSNumber numberWithDouble:temp1];
tempSet.leftFoot = [NSNumber numberWithDouble:temp2];
[footData addObject:tempSet]; //add dataSet object to the array
[tempSet release];
I read some tutorials about memory management online and was able to figure out that I needed to do this: (notice the added "autoreleases")
DataSet *tempSet = [[DataSet alloc] init];
tempSet.rightFoot = [[NSNumber numberWithDouble:temp1] autorelease];
tempSet.leftFoot = [[NSNumber numberWithDouble:temp2] autorelease];
[footData addObject:tempSet]; //add dataSet object to the array
[tempSet release];
I am still confused about why I had to do this. I did not use alloc, new or copy when creating the numberWithDouble.
Does this mean that I would need to add autorelease in this situation as well?:
[subset addObject:[NSNumber numberWithDouble:temp]];
What about this situation?:
tempSet.rightFoot = [NSString stringWithString:#"temp"];
I appreciate any help.
+numberWithDouble
is called a convenience method. Meaning, it replaces the little section of code that would look like this:
[[[NSNumber alloc]initWithDouble:double]autorelease];
Most (if not all) convenience methods are auto release by default, so the OP code with the autoreleases is incorrect, as it drops the retain count to -1.
The equals sign however is equivalent to
[self setRightFoot:[[[NSString alloc]initWithString]autorelease]];
which increments rightFoot's retain count and requires it to be released elsewhere.
as for the -addObject code, it returns void, so it does not in fact increment the receiver's retain count, and requires no release of the receiver. The object in the array should already be released by the convenience method for later, which doesn't matter because the array is now holding "copy" of it.
This is not an answer (I just do not know how to comment -- I only see "share, edit, flag"), but just a few info about Memory Management in iOS:
1. Don't release objects that you do not own.. ---> owned objects are usually the ones you "alloc", "new", "copy." //And probably the one in your #property wherein you "retain" an object.
2. when you "autorelease" an object, don't "release" it afterwards, because that would mean you're releasing the same object twice.
But there's ARC already, so you better upgrade your Xcode to avoid overreleasing objects / memory leaks (for not releasing objects)..
If there's something wrong or inappropriate with the one I put here, please edit. :)

regarding use of nonatomic and retain property

I've a NSMutableArray in AppDelegate
I'm using property (nonatomic,retain)
and synthesizing it
again in didfinishlaunch allocating it using [[nsmutablearray alloc]init];
So, my doubt is if I'm releasing it in deallloc using release method.
is it released properly?
or still retain count is there.
if I'm doing wrong kindly provide a proper solution.
It depends on how you're assigning it. If your assignment is directly to the ivar, like
myProperty = [[NSMutableArray alloc] init];
Then a single release in dealloc is adequate, because you have an expected retain count of 1 from the alloc.
On the other hand, if you have used a synthesized setter via either:
[self setMyProperty:[[NSMutableArray alloc] init]];
or
self.myProperty = [[NSMutableArray alloc] init];
then you have almost certainly leaked the object. You incremented the retain count twice (once via alloc and once in the setter) and only decremented it once (in dealloc).
Best IMO is to use the setter and the autorelease pool:
self.myProperty = [[[NSMutableArray alloc] init] autorelease];
Here the alloc is balanced with a local autorelease, and the setter`s retain is balanced with the dealloc release.
While that approach involves two extra methods (the setter method and the autorelease call), it ensures that any retained values that were formerly set in the the property are released as necessary (in the setter method).
Yes, you still need to release it in dealloc.
These two pages are must-reads for iOS/Cocoa developers regarding memory management
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
For your specific example, see the section on the second link called "Implement dealloc to Relinquish Ownership of Objects"
Here is also a link to this issue addressed on Stack Overflow:
Understanding reference counting with Cocoa and Objective-C
If you do something like:
my_property = [[NSMutableArray alloc] init];
The 'my_property' assumes ownership of your array. Your class's dealloc method has to release the array to prevent leaks.
[my_property release];
-or-
self.my_property = nil;
If you are using
[self setMutableArray:[[nsmutablearray alloc] init]];
in this case it will release any memory which is previously assigned to it(give up ownership).
so in dealloc method you are simply
writing
self.mutableArray = nil;
then it will give up the ownership and memory allocated to mutableArray will be released automatically
In your case the retain count will be 2 and the array keeps releasing. When you have set the property you do not need to initialise it .

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 in 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.