I'm constructing a small iphone app and using a singleton to store and update a string that gets updated when the user taps letters or numbers on the screen to form a code.
i.e. they tap 3 then S then 4 and I need to track and combine that input to give me "3S4" say. When the singleton is initialised it creates an empty NSString and I then use the stringByAppendString method to add on the next letter/number tapped. When I first tried this I did not have the [enteredCode retain] line in there and the app would crash with EXC_BAD_ACCESS, always after 2 inputs. I set the NSZombie property which told me that the enteredCode had been de-allocated but I don't know where or how that happened. All I know is that at the end of the addInput method it will report the retainCount to be 2 say and then straight after I can see (by calling the singleton from elsewhere) it will drop down to 1 (when the retain line is in there).
My question is: though what I've done by adding [enteredCode retain] works for me am I breaking some rules here or going about this in the wrong/bad way? I just can't see why the string is being released.
I'm new to Objective-C btw
in MySingleton.h
#interface MySingleton : NSObject {
NSString *enteredCode;
}
in MySingleton.m
-(void) addInput:(NSString *) input
{
NSLog(#"enteredCode retain count is : %d \n ",[enteredCode retainCount]);
enteredCode = [enteredCode stringByAppendingString:input];
NSLog(#"enteredCode retain count is : %d \n ",[enteredCode retainCount]);
[enteredCode retain]; // without this the app crashes
NSLog(#"enteredCode retain count is : %d \n ",[enteredCode retainCount]);
}
-(id) init
{
self = [super init];
if (self)
{
enteredCode = #"";
}
return self;
}
First, never use the -retainCount method. The absolute count of retains on an object is an implementation detail of the frameworks and will often return confusing results.
Retain counts are something you should maintain entirely as a balanced set of deltas. If you cause a retain count to be added to something, you must release or autorelease that object somewhere. End of story.
This document explains it all.
With that knowledge in hand, the source of your crash is a fairly common memory management mistake.
enteredCode = [enteredCode stringByAppendingString:input];
Every time that line of code is executed, you are replacing enteredCode with an autoreleased instance of NSString. The autorelease pool is drained and your program crashes the next time enteredCode is used.
Your solution of retaining enteredCode is only half the solution. You need to ensure that the original value of enteredCode is released, too. See the memory management docs.
If this were my app, I would turn enteredCode into an #property that copies the string and always set and access enteredCode through that property, never retaining or releasing it manually in my code (outside of -dealloc, of course).
NSString's stringByAppendingString: returns a new NSString made by appending one string to the other, and the new NSString is set to autorelease, which empties the autorelease pool and your next run crashes the app. You're redefining an existing string with stringByAppendingString:, and that's causing the retain problems. (Alternatively, use NSMutableString and you can avoid this.)
By the way, you can do if (self = [super init]) in your init override. The declaration returns true if it occurs or can occur.
Here's how your code should look:
#interface MySingleton : NSObject {
NSString *enteredCode;
}
#property (nonatomic, retain) NSString *enteredCode;
#end
#synthesize enteredCode;
-(void) addInput:(NSString *) input
{
self.enteredCode = [self.enteredCode stringByAppendingString:input];
}
- (void)dealloc {
[enteredCode release];
}
#end
Related
This question already has answers here:
Objective C NSString* property retain count oddity
(9 answers)
Closed 9 years ago.
here is the following program about increasing d retain count value of a NSString type variable
in interface part I have declared
#property (strong,nonatomic)NSString *str1;
#property (strong, nonatomic)NSString *str2;
-(IBAction)goBtn:(id)sender;
and ind implementation part I have defined following
- (IBAction)goBtn:(id)sender {
self.str1=[[NSString alloc]init];
self.str1=self.str2;
self.str2=[self.str1 retain];
self.str2=[[NSString alloc]init];
self.str2=self.str1;
self.str1=[self.str2 retain];
self.str2=[self.str1 retain];
NSLog(#"retain count is %i", self.str1.retainCount);
NSLog(#"retain count of str2 is %i", self.str2.retainCount);
}
but the output is
retain count is 0
retain count of str2 is 0
why is this happening?? is there anything wrong in codes???
You are sending a lot of messages to nil and that is why you are getting a 0 for the retain count.
Here I wrote down your code again with the new values for your variables when they change:
str1 and str2 are nil
self.str1=[[NSString alloc]init];
str1 is empty string
self.str1=self.str2;
str1 is nil
self.str2=[self.str1 retain];
self.str2=[[NSString alloc]init];
str2 is empty string
self.str2=self.str1;
str2 is nil
self.str1=[self.str2 retain];
self.str2=[self.str1 retain];
In the end both str1 and str2 are nil giving you a zero retain count.
But even if you didn't overwrite your new strings with nil every time you wouldn't get the expected result. Lets consider this:
self.str1 = [[NSString alloc] init]
self.str2 = [[NSString alloc] init]
If you look at their retain count you'll get 18446744073709551615 (on Mac OS X, 64 bit) for each. If you then look at the values of the pointers you'll see that they both are equal, so you got the same empty NSString object both times you called [[NSString alloc] init].
That actually makes sense. NSString objects are immutable, that means once they are created they cannot ever change. So there is no point in wasting memory on multiple identical copies of the empty string.
Some of those shared instances return the biggest possible value from their retainCount method to show the fact that they are singletons. But not all of them.
So the retain count of objects is not very useful. Some objects lie about it. And in real apps it still often is not what you'd expect. Sometimes the system holds on to objects for some time, even if you didn't retain it yourself.
But I guess you are trying to learn how the retain/release memory model works (which is necessary, even if you are using ARC). For this you can get away with querying the retain count. But then you should use the base class NSObject directly, because it doesn’t do any special tricks with the retain counter. And you need to keep in mind that as soon as you pass your test objects to some system methods your retain count could be something unexpected later. Always keep in mind to never query the retain count in a real app - it is useless.
Retain count is meaningless. Don't worry about it. It gets into a lot of complicated factors like the fact that NSString is a class cluster and the implementation details are really not your problem.
More importantly, your property is declared incorrectly.
Automatic Retain Count (ARC)
#property (strong, nonatomic) NSString *ARCString;
Retain/Release
#property (retain, nonatomic) NSString *retainString;
Further discussion
As Sven (below) points out retain and strong are synonymous technically. However, I think it is important to distinguish when code is under ARC or Retain/Release. Some general best practices:
Only refer to the ivar in init and dealloc using _ivar and here use a call to retain/release if not using ARC. No need for dealloc under ARC.
- (id)initWithString:(NSString *)string
{
self = [super init];
if (self != nil) {
_retainString = [string retain]; // Adds 1 to retain count
}
return self;
}
- (void)dealloc
{
[_retainString release]; // Decrement retain count by 1
[super dealloc];
}
The rest of the time make the call to the getter/setter using self.ivar. This takes care of the correct behavior automatically.
- (void)doSomethingWithString:(NSString *)string
{
self.retainString = string; // Adds 1 to retain count
}
If and when you decide to override the getter/setter in your declared property, then you will refer to the _ivar and manually call retain or release. If using ARC the call to retain/release is unnecessary.
- (void)setRetainString:(NSString *)string
{
if (_retainString != string) {
[_retainString release];
_retainString = [string retain];
}
}
You should always Analyze your code to verify you haven't screwed something up in an obvious way. It will often reveal failures in your logic.
I used the leaks tool in Instruments to test the code, but the leaks tool cannot seem to find the leak.
At the end of my code, the output of NSLog(#"str count:%d",[str retainCount]); is 3. Why? I don't override the dealloc. [a.name retainCount] is there just one time
and I only autorelease str for one time. So str shouldn't leak.
#interface DataMode : NSObject {
NSString * name;
}
#property (retain) NSString * name;
- initWithName:(NSString * )name_;
#end
#implementation DataMode
#synthesize name;
- initWithName:(NSString * )name_
{
if ([super init] != nil)
{
name = name_;
return self;
}
return nil;
}
#end
- (void) pressed:(id)sender
{
for( int i = 0;i<10000000;i++)
{
NSString * str = [NSString stringWithFormat:#"zhang"];
DataMode * a = [[DataMode alloc] initWithName:str];
NSLog(#"a0 count:%d",[a retainCount]);
NSLog(#"name1 count:%d",[a.name retainCount]);
NSLog(#"name1 count:%d",[a.name retainCount]);
NSLog(#"a1 count:%d",[a retainCount]);
[ a release];
NSLog(#"str count:%d",[str retainCount]);
NSLog(#"str count:%d",[str retainCount]);
}
}
#end
retainCount is useless. Don't call it.
It is not useful for finding leaks as there are much better, more accurate, and less misleading tools available.
There are several problems with your code (but leaking isn't one of them):
NSString* properties should be copy
you don't use the property to set the string value in init, thus the DataMode instances are not retaining their strings.
there is no dealloc method
As for the retain counts; I'm surprised it is "3". I'd expect it to be 2bazillionsomething as that is a constant string (and stringWithString: of a constant string just returns the string).Since you used stringWithFormat:, the constant string is turned into a non-constant string. If you had used the constant string or stringWithString:, it'd be abazillionsomething (unsigned -1... UINT_MAX...).
In any case, you have:
+1 for stringWithString:
+1 for calling a.name
+1 for calling a.name
+3 overall.
If Instruments is claiming a leak, post a screenshot.
I quote the NSObject protocol reference for -retainCount:
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.
The retain count could be 3 for any number of reasons; if you can't find a leak with the leaks tool, it's likely you don't have a leak. Don't worry about the actual value of the retain count.
If you're really interested in why it's 3, recall that:
The reference from your DataMode object a will likely be held until the closest autorelease pool is drained
You're still holding a reference in the str variable
The NSString class cluster, among others, does some - unusually inexplicable - caching things internally, so you may see a few retains here and there for which nobody can account
Since you are using the convenience method to create str which is autoreleased you will not see determinate behavior using retain counts in this way.
Check my response to another question and add those methods to DataMode and you should see when the framework releases your objects from the autorelease pool.
Overriding release and retain in your class
I'm going through all of my documentation regarding memory management and I'm a bit confused about something.
When you use #property, it creates getters/setters for the object:
.h:
#property (retain, nonatomic) NSString *myString
.m:
#synthesize myString
I understand that, but where I get confused is the use of self. I see different syntax in different blogs and books. I've seen:
myString = [NSString alloc] initWithString:#"Hi there"];
or
self.myString = [NSString alloc] initWithString:#"Hi there"];
Then in dealloc I see:
self.myString = nil;
or
[myString release];
or
self.myString = nil;
[myString release];
On this site, someone stated that using self adds another increment to the retain count? Is that true, I haven't seen that anywhere.
Do the automatic getters/setters that are provided autorelease?
Which is the correct way of doing all of this?
Thanks!
If you are not using the dot syntax you are not using any setter or getter.
The next thing is, it depends on how the property has been declared.
Let's assume something like this:
#property (nonatomic, retain) Article *article;
...
#synthesize article;
Assigning something to article with
self.article = [[Article alloc] init];
will overretain the instance given back by alloc/init and cause a leak. This is because the setter of article will retain it and will release any previous instance for you.
So you could rewrite it as:
self.article = [[[Article alloc] init] autorelease];
Doing this
article = [[Article alloc] init];
is also ok, but could involve a leak as article may hold a reference to an instance already. So freeing the value beforehand would be needed:
[article release];
article = [[Article alloc] init];
Freeing memory could be done with
[article release];
or with
self.article = nil;
The first one does access the field directly, no setters/getters involved. The second one sets nil to the field by using a setter. Which will release the current instance, if there is one before setting it to nil.
This construct
self.myString = nil;
[myString release];
is just too much, it actually sends release to nil, which is harmless but also needless.
You just have to mentally map hat using the dot syntax is using accessor methods:
self.article = newArticle
// is
[self setArticle:newArticle];
and
myArticle = self.article;
// is
myArticle = [self article];
Some suggestions on reading, all official documents by Apple:
The Objective-C Programming Language
Dot Syntax
Declared Properties
Memory Management Programming Guide
Object Ownership and Disposal
Using Accessor Methods
When you create a retain setter, you're creating something like this:
- (void)setString:(NSString *)someString {
if (someString != string) {
[string release];
[someString retain];
string = someString;
}
}
If you don't use the setter, the new value is not getting that retain—you don't "own" that string, and because it's all references, if the original string is released, you might be facing a null reference, which will lead to an EXC_BAD_ACCESS. Using the setter ensures that your class now has a copy of that value—so yes, it does increment the retain count of the new value. (Note that using the getter is a convention of OOP—that outsiders should not be able to directly touch the ivar. Also in your getter you can modify the value, maybe returning an NSArray when your ivar is an NSMutableArray, for example).
You shouldn't autorelease in a setter—Apple has used it in their sample code, but a thing to keep in mind is that setters are called a lot—millions of times, potentially. All of those objects are going into the same autorelease pool, so unless you create your own and/or regularly flush it, you'll have a ton of elements in your pool, all unneeded but still taking up RAM. Much better to simply release.
As for dealloc, trace back through that setter. If you send a release directly, it's obvious—you release that object. But if you write self.string = nil;, what you're doing is this:
The nil value is not the same, so you enter the if block
You release the old value—what you want to do
You retain nil: messages to nil do nothing, and you don't crash
You set nil, which doesn't take up any memory, to the string, which is now effectively empty
As a matter of convention, I use release in my dealloc method, because release seems more final, and dealloc is the final method call your object will receive. I use self.string = nil; in viewDidUnload and the memory warning methods.
Hope this helps!
In addition to Nick's answer - synthesized getters/setters don't provide autorelease (btw, what's the big idea of doing this? Well, you can use getter as a factory, but it's not a common way in Objective C).
Then in dealloc I see:
self.myString = nil;
or
[myString release];
or
self.myString = nil; [myString
release];
In dealloc it doesn't really matter which form of release you're using. But the good way is to nil your fields when releasing them :) I prefer to use self.myString = nil; in dealloc
.h
# interface MyClass : NSObject {
UILabel *mTextLabel;
}
#property (nonatomic, retain) UILabel *mTextLabel;
and Declare #synthesize mTextLabel in the MyClass.m;
and release the object like this.
[self setMTextLabel:nil];
[mTextLabel release];
NSLog (#"%d",[mTextLabel retainCount]);
This result is 0. and I have not found any error or interrupt.
But. When I release mTextLabel like this. I have just got EXC_BAD_ACCESS
[mTextLabel release];
[self setMTextLabel:nil];
I don't understand why it happen. Plz help me.
When you have a synthesized property with the retain attribute, the synthesized setter calls release on the old ivar before it sets the new value.
Here is an expanded view of what is happening in the first example:
[mTextLabel release];
mTextLabel = nil;
[mTextLabel release];
Since calling a method on a nil pointer does nothing, there is no problem.
In the second example, here is what is happening:
[mTextLabel release];
[mTextLabel release];
mTextLabel = nil;
See the problem?
Edit: it is also worth noting that inspecting the retain count of an object is rarely useful, as any number of Cocoa classes may retain it for their own purposes. You just need to be sure that every time you call retain, alloc, copy or new on an object, there is a matching release or autorelease somewhere in your code.
The problem is you are calling release then you are setting the property to nil which also sends a release to mTextLabel before setting it to nil. This is what happens when the property is defined as copy or retain. All you need is the following code.
[mTextLabel release];
mTextLabel = nil;
Edit:
I would like to add that in your code outside of init and dealloc it is completely fine to call self.mTextLabel = nil to properly release if necessary and nil the value of the property. It is however recommended to NOT use the property in the init/dealloc calls. In those cases you will want to create / release the objects directly to avoid the side effects of the accessor.
The value is already released when you do [self setMTextLabel:nil]. You don't need to release the value explicitly (unless you created the value using an init or copy method, in which case you should release it as soon as you've assigned to self.mTextLabel).
Note that retainCount has a return type of NSUInteger, so cannot ever be negative. So checking to make sure the retain count is zero and not -1 doesn't work.
I'm slowly teaching myself cocoa for the iPhone(through the Stanford Class on iTunes U) and I've just gone through the part on memory management, and I wanted to hopefully get some confirmation that the assumptions I'm making on how memory is handled and how [release] and [autorelease] work. Since memory management is a really basic and fundamental, but very essential part of the programming experience, I'd like to make sure I'm doing it right.
I understand that anything with an alloc, new, or copy needs to be released.
If I do this:
NSString *temp = [[NSString alloc] initWithString:#"Hello World"];
Then I need to add [temp release/autorelease] eventually, since I have an alloc.
However, if I do this:
NSString *temp = #"Hello World";
Then it doesn't seem to need a release statement. Does the NSString class call autorelease automatically as part of the assignment?
Also, is there any difference between the two *temp objects here after these statements? They both contain the same string, but are there memory/usage ways where they differ?
Secondly, with properties, I'm assuming that the autorelease is handled automatically. If I have this:
#interface Person : NSObject
{
//ivars
NSString *firstName;
NSString *lastName;
}
//properties
#property NSString *firstName;
#property NSString *lastName;
///next file
#implementation Person
#synthesize firstName;
#synthesize lastName;
- (void) dealloc
{
//HERE!!!!
[super dealloc];
}
I'm assuming I don't need to add [firstName release] and [lastName release] (at //HERE!!!!), since that's automatically handled by the properties. Is that correct?
I do understand that if I do this in code(assuming I've defined initWithFirstName):
Person *Me = [[Person alloc] initWithFirstName: #"Drew", lastName:"McGhie"];
that later I'm going to have to use [Me release/autorelease];
Any help confirming or correcting my understanding so far is greatly appreciated.
POST ANSWER WRITE-UP
I thought I'd write this all up after going over all the answers and testing out the suggestions and talk about what worked.
I do need to add the [firstName release], [lastName release], but I also need to add (retain) to the property descriptions. Not adding the (retain) caused warnings because it assumes (assign). Here's how I finally set up the class
#interface Person : NSObject
{
//ivars
NSString *firstName;
NSString *lastName;
}
//properties
#property (retain) NSString *firstName;
#property (retain) NSString *lastName;
///next file
#implementation Person
#synthesize firstName;
#synthesize lastName;
- (void) dealloc
{
[firstName release];
[lastName release];
[super dealloc];
}
The rule is simple: if you alloc, copy or retain, it's your responsibility to release. If you didn't, it's not. However, if you need to rely on an object staying around, you have to retain (and subsequently release).
We can treat the string literal according to the rules - you don't need to release it because you don't own it. That's simple; there's no need to worry about whether they're special cases or not, just follow the rules and you'll be fine.
I wrote up a blog post with a collection of articles about the Cocoa memory management rules; I'd recommend following up some of the references.
I've never released string constants like NSString *foo = #"x";. Logically, if you had to release the result of that, it you would have to release the parameter to initWithString, and both the parameters to initWithFirstName:lastName:, too.
You must do release or autorelease firstName and lastName. I've seen warnings about not using property syntax in destructors, which I think is the same reason you don't use virtual functions in C++ constructors and destructors.
Your assumption was wrong. You must do either this:
Person *Me = [[Person alloc] initWithFirstName: #"Drew"
lastName: #"McGhie"];
...
[Me release];
or this:
Person *Me = [Person personWithFirstName: #"Drew"
lastName: #"McGhie"];
...and make sure your Person object handles +personWithFirstName:lastName: correctly, i.e. [[[self alloc] initWithFirstName: firstName lastName: lastName] autorelease].
You should probably do the one with less code. Clarity is important, NSAutoreleasePool will probably never be your bottleneck, and if it ever is it's easily fixed.
I think people put a lot of effort into avoiding the class messages that return an autorelease'd object that just isn't merited. It's premature optimization, in that it probably isn't necessary and may not even be the correct thing to do. And it's harder to maintain, you'll very likely be chasing leaks forever.
Also, you're going to autorelease an object you had to init (i.e. alloc + initPersonWithFirstName:lastName: instead of using a class message like personWithFirstName:lastName:), I'd suggest you do it immediately. Otherwise, you're potentially chasing that same kind of leak. So if you're not going to add a personWithFirstName:lastName: method to Person, do this instead:
Person *Me = [[[Person alloc] initWithFirstName: #"Drew"
lastName: #"McGhie"] autorelease];
Summary: Cocoa does a lot to help you with memory management. Make sure you don't fight it.
Updated based on Jon's feedback in comment.
NSStrings created with the #"String here" syntax are constant strings. These are different from normal strings. Much like normal C constant strings, they are created when your program loads and exist for its entire lifetime. The NXConstantString class, to which they belong, ignores all memory management messages. You can retain and release them all you like and it won't make any difference.
For a string created with an [[NSString alloc] initWith...]-type method, normal memory management rules apply. I'd strongly recommend reading the linked docs — they're not complicated, and after reading them, you will know pretty much everything you will ever need to know about Cocoa memory management.
Last part first: You will indeed have to auto/release Me. However, you will also have to add [firstName release]; and [lastName release]; in -dealloc; or better yet; self.firstName = nil;
As for string literals; this part gets a bit hairy, but [#"String literal" release] is essentially a noop. As such, there is a difference between the two temp objects, but as you won't generally know which one you'll be dealing with, adding [temp release]; is generally the safe choice, unless you know it'll contain an autoreleased object.
About firstName/lastName.
You should always, for clarity, remember to specify the properties' attributes. The setter default attribute is assign, in this case you want to use retain.
#interface Person : NSObject
{
NSString *firstName;
}
#property (retain) NSString *firstName;
#end
With retain each and only time you use the dot notation to assign a value the compiler inserts a retain: just remember to always use it. For consistency I advice you to write your initializer this way:
- (id) initWithFirstName:(NSString*) aString
{
self.firstName = aString;
}
and the dealloc method this way:
- (void) dealloc
{
self.firstName = nil;
}
About #""-type objects. They are constant NSStrings objects. Just use them as the were (they are) NSString objects and never release them. The compiler takes care of them.
Does the NSString class call autorelease automatically as part of the assignment?
The NSString class didn't do anything because you didn't send it a message. All you did was assign to a variable. NSString doesn't find out about this, and it's none of its business.
Also, is there any difference between the two *temp objects here after these statements? They both contain the same string, but are there memory/usage ways where they differ?
They're both NSStrings, they both contain the same value, and they're both presumed immutable. That's all you should ever care about.
Secondly, with properties, I'm assuming that the autorelease is handled automatically. If I have this:
#property NSString *firstName;
#property NSString *lastName;
- (void) dealloc
{
//HERE!!!!
[super dealloc];
}
I'm assuming I don't need to add [firstName release] and [lastName release] (at //HERE!!!!), since that's automatically handled by the properties. Is that correct?
No. NSObject will not release all your property values for you; you still need to release them yourself there.
Also, don't do self.firstName = nil and self.lastName = nil in dealloc. Those translate into messages (to your accessor methods), and when you do that in dealloc, you're sending messages to a half-deallocked object. That's asking for trouble. The same applies the other way to initializing property values in init: Using your properties/accessors there would be sending messages to a half-inited object.