NSNumber weirdo ....? - iphone

for a day now I stare at the following routine and can't get my grips around it. I have a class such as:
MyClass.h
...
#interface MyClass : NSObject {
NSNumber *myNumber1;
NSNumber *myNumber2;
}
#property (nonatomic, retain) NSNumber *myNumber1;
#property (nonatomic, retain) NSNumber *myNumber2;
#end
and the m-file
#import "MyClass.h"
#synthesize myNumber1, myNumber2;
#implementation MyClass
-(id) init {
self = [super init];
NSLog(#"Retain Counts myNumber1: %d, myNumber2: %d", [myNumber1 retainCount], [myNumber2 retainCount]);
myNumber1 = [NSNumber inbitWithint:10];
myNumber2 = [NSNumber inbitWithint:2];
NSLog(#"Retain Counts myNumber1: %d, myNumber2: %d", [myNumber1 retainCount], [myNumber2 retainCount]);
return self;
}
...
I use this class as a globals container and instantiate it from every other class in my app using a
MyClass *myGlobals = [[MyClass alloc] init];
===>>> the weirdo >>>
Running the routine I have the following facinating console output:
Retain Counts (before) - myNumber1: 0, myNumber2: 0
Retain Counts (after) - myNumber1: 1, myNumber2: 26
How can that be?

Do not call `retainCount`
The return value of retainCount can only be considered accurate if you are calling it on an instance of a class you wrote and you have never ever not even once passed said instance to any API provided by the system.
The absolute retain count is an implementation detail for which you might not have any control.
Assuming, for the moment, that your code was typed and, thus, the errors are not really in your original code...
NSNumber caches a subset of common values. That is, for some numeric values, there is a single instance of NSNumber that is returned for all requests to retrieve an NSNumber instance wrapping that number.

If this is your actual code, it shouldn't work at all, it should simply crash. If not, you should cut and paste your actual code.
However, a couple of things.
First, if you use an NSNumber as an ivar, like anything else, you must take ownership of it. If you plan to use a convenience constructor, you must either assign it using the property on self, or send it an explicit retain message.
Second, you typed something like initWithInt: here. If you are actually using that message, then you have never actually allocated the number in the first place. You must replace this with one of the following:
myNumber1 = [[NSNumber alloc] initWithInt:10]; // explicitly create the number
myNumber1 = [[NSNumber numberWithInt:10] retain]; // take ownership through retain
[self setMyNumber1:[NSNumber numberWithInt:10]]; // use the property accessors to deal with ownership and the convenience constructor to create the number
However you choose to do it, you must at some point take ownership of the object.

You should never even look at retainCount as it carries little significance anyway. The reason you see the count of 26 is that probably somewhere in the frameworks (or even in your own app) other instances of NSNumber exist that are created with the same int 2. An NSNumber is immutable, and so as an optimization NSNumber probably just gives you back an instance it has created earlier. As long as you don't look at retainCount it doesn't matter to you.

Related

how retain count of NSString type variable is increased? [duplicate]

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.

Instruments says I'm leaking a string, but I can't find it

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

assignment of property and allocation leads to retain count of 2

I had a look at instruments and I saw that the alloc increased the retain count by 1. So far everything clear. But the assignment of the class to my property also increased the retain count to 2.
self.myProperty = [[MyClass alloc] init]
Vs.
MyClass *myCreatedVariable = [[MyClass alloc] init];
self.myProperty = myCreatedVariable
To decrease the retain count to zero I released myCreatedVariable right after my calls. The myProperty instance variable is released in the dealloc method. Am I right that a property only is released in the dealloc method?
Now to my question:
Is the allocation and the assignment to a property always creating a retain count of 2? So don't use
self.myProperty = [[MyClass alloc] init]
because the retain count is never getting zero? Or is this only the case if I'm allocating a class?
Cheers
Your property is most probably declared as retaining or copying:
#property (retain) MyClass myProperty;
or
#property (copy) MyClass myProperty;
This calls your setter that does what its attributes say: retain! Copy will also retain.
Although it worked here, you shouldn't try to get useful information out of the retainCount property.
I cannot recommend the Memory Management Programming Guide highly enough, well worth a first, second and third read. :-)
Creating objects using the init function returns a retained instance by default. ( See the Memory Management Programming Guide)
If the property is defined with the 'retain' attribute, then your object is retained one more time.
So the right way to do is
MyClass *myCreatedVariable = [[MyClass alloc] init];
self.myProperty = myCreatedVariable;
[myCreatedVariable release];
By the way this is good to know also when you using Arrays.
Once an object created with the alloc and init functions is added into an array, it is retained by the array, so you can release your instance after you add it in the array.
In both case, retainCount is then 1, as expected.
if your property is defined with the 'copy' attribute, you can release the object as well, and even kill it, since it has been fully copied and retained once.
( I think there is something there if you use garbage collection instead of managed memory... To check.. )
Finally if your property is set with the 'assign' attribute, only the object's adress is copied, so you should not release your original object in this case.
It is however not recommanded to use the 'assign' attribute, since you may set property with objects that you did not create yourself, and which could be released anytime, letting your property pointing in the fields...
Finally, don't forget that static creators in Cocoa do not return retained objects.
( This is a convention, exceptions may exist... )
example:
NSArray* myArray = [NSArray array];
self.myProperty = myArray;
In this case, do not release myArray, it is already done in the creator function.
Assigning it to the property will retain it.( with retain or copy attribute).
Hope it will help,
Cheers
#property (nonatomic, retain) NSString *strURL;
This will keep the Retain count = 0
When you use an accessor to initialize the strURL then the retain count increases to 1
self.strURL = [NSString stringWithString:#"http://192.168.1.25/shop.php"];
However if you had done this without using the accessor then your reference count would have remain same that is 0
strURL = [NSString stringWithString:#"http://192.168.1.25/shop.php"];
Note that when you use this variable with retain count as 0, the auto release works and the variable gets released, giving "SIGABART" error or “EXC_BAD_ACCESS” when you try to access its value.
Generally when you are using init to get your variables initialized the best practice is to use alloc.
strURL = [[NSString alloc] stringWithString:#"http://192.168.1.25/shop.php"];
Hope this helps!
Sorry ? Noooo. I'm afraid programming is trying to know things we don't know everyday !
Static creators are convenience function, to ease common objects allocations.
A lot of classes in the cocoa framework have this kind of functions. Arrays, Dictionary, Paths, ...
Let's take your class as an example, and suppose you often have to create objects of this class. You may write a function in your 'myClass' implementation like:
+(MyClass*)myClass
{
MyClass *myNewInstance = [[myNewInstance alloc] init];
return [myNewInstance autorelease];
}
Then you can rewrite your original example as:
..
self.myProperty = [MyClass myClass];
..
Straight!
Or you could write a method like
-(void)myFunction
{
MyClass* myTempObject = [MyClass myClass];
if (myTempObject) {
// do something with your temporary object
}
// Simply exit, object will be released later on.
}
It is much shorter ( we should handle the case where object creation failed ) ..
Note that this is all conventions, you can basically do has you like and create retained objects, or use a different name for the creator.
But it is safer to follow the framework rule, it then becomes a reflex when you code.
See methods like [NSDictionary dictionary], [NSArray array], [NSArray arrayWithObjects:] ,...
Cheers

Objective C NSString being released in singleton

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

release/autorelease confusion in cocoa for iphone

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.