iPhone memory management(Specially for property) - iphone

I have a very clear question:
//.h file
#property (nonatomic, retain)NSMutableString * retainString;
#property (nonatomic, copy)NSMutableString * copyString;
//.m file
#synthesis retainString, copyString;
-(void)Process
{
NSMutableString *test = [[NSMutableString alloc]inti];//retain count should be 1
self.retainString = test;
self.copyString = test;
}
cond. 1-> // retain count of both should be 2. As they are pointing to the same memory location with retain count 2 so how may release should be written.
cond. 2-> // //retain count of test is 1 and copyString is 2. As both hold different memory location. but can we write [copyString release].

This setup actually does some very interesting things, and raises a couple good points about Objective-C memory management. Let's first reiterate the code:
// Testing.h
#interface Testing : NSObject {
NSMutableString *retainString;
NSMutableString *copyString;
}
#property(nonatomic,retain) NSMutableString *retainString;
#property(nonatomic,copy) NSMutableString *copyString;
// Testing.m
#implementation Testing
#synthesize retainString, copyString;
- (id)init {
if(self = [super init]) {
NSMutableString *test = [[NSMutableString alloc] init];
NSLog(#"test %d; retain %d; copy %d", [test retainCount], [retainString retainCount], [copyString retainCount]);
self.retainString = test;
NSLog(#"test %d; retain %d; copy %d", [test retainCount], [retainString retainCount], [copyString retainCount]);
self.copyString = test;
NSLog(#"test %d; retain %d; copy %d", [test retainCount], [retainString retainCount], [copyString retainCount]);
[self.copyString appendFormat:#"test"];
NSLog(#"test %d; retain %d; copy %d", [test retainCount], [retainString retainCount], [copyString retainCount]);
}
return self;
}
#end
This produces the log output:
2009-12-24 03:35:01.408 RetainCountTesting[1429:40b] test 1; retain 0; copy 0
2009-12-24 03:35:01.410 RetainCountTesting[1429:40b] test 2; retain 2; copy 0
2009-12-24 03:35:01.410 RetainCountTesting[1429:40b] test 2; retain 2; copy 2147483647
2009-12-24 03:35:01.413 RetainCountTesting[1429:40b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with appendFormat:'
So what's going on here? The first two calls are fairly straightforward:
The initial call to alloc/init creates a new NSMutableString object with retain count 1, as expected. We have one object with one retain on it.
The assignment to the retained property increments the retain count, as expected. We have one object with two retains on it.
Here's where it gets strange. The assignment to the copy property does indeed make a copy, but not in the way you'd expect. NSString and NSMutableString are part of what's called a class cluster - when you create or modify a string, it may or may not be an instance of the class you're expecting. The language may mutate it to some other representation behind the scenes.
In this particular case, when the copy is performed, apparently the language decides that the string (since it contains no information) is to be considered immutable, and makes it so. This is often seen when people do something like [[NSString alloc] initWithString:#"hello"] - it's a constant, static string, so no object need be allocated dynamically. Keeping it static helps the runtime perform better.
So now we have two objects: our original test object that was retained twice, and the new object that is static and therefore has a retain count of INT_MAX. Finally, since the new string is immutable, calling a mutator method on it kills the program.
As an aside, changing the original call from init to initWithString: does make the copy assignment perform (somewhat) as expected - you only get a retain count of 1 on the copied object, but you still can't mutate it. Again, this is probably due to some optimization magic inside the compiler that decided that string was static and saw no reason to make it mutable if it didn't have to.
To answer your final question: yes, you can call release on either of these objects. It just won't do much. At best, you'll have destroyed the copied object (since it had a retain count of 1); at worst, it'll do nothing to a static string object. However, I'd recommend continuing to work through properties: rather than releasing the copied object, why not just do self.copyString = nil;? Since it calls the property setter, it'll take care of the release as necessary, and then you don't have a pointer to the object still floating around.
For more information on all this, consider reading:
Memory Management Programming Guide for Cocoa
The NSString class reference
The Objective-C Programming Guide, Declared Properties section

If you have properties defined with keywords 'retain' or 'copy' you should always release corresponding member variables in the dealloc method.
In this case your dealloc should look like this:
- (void)dealloc {
[retainString release];
[copyString release];
[super dealloc];
}
Now, when you alloc a string in your custom class' method, this method owns the string as described in the Memory Management Programming Guide for Cocoa. This means that you should release the string before leaving the method.
#synthesize retainString, copyString;
- (void)Process {
NSMutableString *test = [[NSMutableString alloc] init]; //retain count is 1
self.retainString = test; // retain count of test is 2
self.copyString = test; // test's retain count = 2, copyString's = 1
[test release]; // retain count of test is 1 again
}
When an instance of this class is destroyed, the dealloc method will be invoked which will in turn release both strings. And as soon as their have retain counts remain 1, they will be dealloc'ed too.

This may also help
NSString property: copy or retain?

Related

IOS retain , Assign

I observed the following behavior.
Took two property variables.
#property (nonatomic, retain) NSString *stringOne;
#property (nonatomic, assign) NSString *stringTwo;
In .m file written below code..
NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"];
self.stringOne = localstring;
NSLog(#"localstring = %d", [string retainCount]);
NSLog(#"string one retain count = %d", [self.stringOne retainCount]);
self.stringTwo = localstring;
NSLog(#"localstring = %d", [localstring retainCount]);
NSLog(#"string two retain count = %d", [self.stringTwo retainCount]);
Here localstring retain count is 1 because of alloc. Now i gave
self.stringOne = localString.
The retain count of localstring will become two because of retain property of stringOne. Now i gave
self.stringTwo = localString.
Even here the localstring retain count is incremented by one. Notice that i have given assign property to stringTwo. Practically the retain count of localstring or stringTwo should not increase by 1 as it is assign property.
Please correct me if i am wrong.
Thanks
Jithen
Dump the retainCount; it is useless. http://www.whentouseretaincount.com/
The source of your confusion is in not understanding how pointers work. Modify your code like this:
#interface BBQ:NSObject
#property (nonatomic, retain) NSString *stringOne;
#property (nonatomic, assign) NSString *stringTwo;
#end
#implementation BBQ
- (void) burn
{
NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"];
self.stringOne = localstring;
NSLog(#"localstring = %p", localstring);
NSLog(#"string one = %p", self.stringOne);
self.stringTwo = localstring;
NSLog(#"localstring = %p", localstring);
NSLog(#"string two = %p", self.stringTwo);
}
#end
It'll spew something like this:
2013-04-11 08:48:13.770 asdffadsfasddfsa[18096:303] localstring = 0x10010aaf0
2013-04-11 08:48:13.772 asdffadsfasddfsa[18096:303] string one = 0x10010aaf0
2013-04-11 08:48:13.772 asdffadsfasddfsa[18096:303] localstring = 0x10010aaf0
2013-04-11 08:48:13.772 asdffadsfasddfsa[18096:303] string two = 0x10010aaf0
There is only one string instance in play; localstring, stringOne, and stringTwo all hold references to exactly one instance of NSMUtableString.
Thus, you'll see +1 RC of that one string instance for the alloc, +1 for the assignment to the stringOne property and no change for stringTwo.
(RC's should only be reasoned about in terms of deltas; if you retain an object, you need to balance that with a release when you no longer need the object. That the object may be retained by something else is irrelevant.)
When I ran this code:
#interface ViewController ()
#property (nonatomic, retain) NSString *stringOne;
#property (nonatomic, assign) NSString *stringTwo;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self test];
}
- (void)test
{
NSMutableString *localstring = [[NSMutableString alloc] initWithString:#"test"];
NSLog(#"localstring (before setting `stringOne` or `stringTwo`) = %d", [localstring retainCount]);
self.stringOne = localstring;
NSLog(#"localstring (after setting `stringOne`) = %d", [localstring retainCount]);
NSLog(#"string one retain count = %d", [self.stringOne retainCount]);
self.stringTwo = localstring;
NSLog(#"localstring (after setting `stringTwo`) = %d", [localstring retainCount]);
NSLog(#"string two retain count = %d", [self.stringTwo retainCount]);
}
#end
I received this console log:
localstring (before setting `stringOne` or `stringTwo`) = 1
localstring (after setting `stringOne`) = 2
string one retain count = 2
localstring (after setting `stringTwo`) = 2
string two retain count = 2
And all of those values are precisely as one would expect.
When you first create the object referenced by the local variable, that object has a +1 retain count.
When you set the retain property, stringOne, the object's retain count will be incremented to +2, and as both localstring and stringOne reference that same object, they'll both report the same retainCount.
But when you use the assign property, stringTwo, though, the retainCount does not change.
When you declare a property with retain, it automatically 'retains' the object, thus increasing its retain count.
So NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"]; makes retain count = 1;
Then self.stringOne = localstring; makes retain count = 2.
My thinking is if the property is given retain, then after this line
self.stringOne = localstring , the retain count of self.stringone
should become one
When you create an object, it will start with a retain count of 1.
First of all, never use retainCount for anything. It is simply not reliable since it is a global retain count, and can be influenced by other factors outside of your code. Amazingly, in this case, it is correct though. Let's examine:
//Immediately localstring is +1 because you allocated it
NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"];
//self.stringOne is a retain property, so localstring is incremented again (+2)
self.stringOne = localstring;
//self.stringTwo is a retain property, so localstring is incremented again (+3)
self.stringTwo = localstring;
Note that now localstring, self.stringOne and self.stringTwo all point to the same location in memory. You are not copying the memory contents every time you use the = sign (your way of thinking seems to indicate that you think that is how it works). You are simply pointing another variable at a location in memory and saying "Don't deallocate this piece of memory until I say so." (at least in the case of retain properties).
Conclusion: localstring's retain count, self.stringOne's retain count, and self.stringTwo's retain count are all the same.
Sidenote: It is impossible for an object to have a retain count of zero. The only time that can happen is when retainCount is sent to nil (which I assume self.stringOne is when you test it)
While it is never a good idea to look at retainCount when writing code, it is behaving as it should in this case. I think your understanding of memory management seems to be a little bit off.
To answer your question,
NSMutableString *localstring= [[NSMutableString alloc] initWithString:#"test"];
This creates a mutable string Object,increments its retain count and returns a pointer to it. Note that retainCount is associated with the Object and not the pointer.
When you assign it to your retain property,
self.stringOne = localstring;
it passes retain to your Object and increments its retain count by 1 again. Now your object's retain count is 2 and both the pointers point to the same object. So, when you log retainCount, you get what you get. Hope this answers your question.

Explain alloc/init occurring twice

I realize this question may sound dumb, but just bear with me. I built an app to help new developers wrap their head around memory retention on the iPhone (no ARC yet). It is plain and simple, 4 buttons, init, access, retain, and release. Pretty self explanatory. I am displaying what the retain count for my string object that is the target of our poking and prodding. (Please no lectures on use of [myVar retainCount], I already know)
This stuff will never make it into actual apps, just toying with it for fun and hopefully help someone learn how memory works. My retain and release all work great. My question is that why does my retain count drop back to 1 if I call myString = [[NSMutableString alloc] init]; again. I can boost my retain count to 40, but after calling alloc/init I go back to zero. I am not leaking anywhere, just curious what happens to myString if/when alloc/init is called on it again.
My question is that why does my retain count drop back to 1 if I call
myString = [[NSMutableString alloc] init]; again?
Because you are failing to understand a very basic concept of Objective-C; myString is not an instance of an NSMutableString, but a reference to an instance. If you were to:
myString = [[NSMutableString alloc] init];
myString = [[NSMutableString alloc] init];
You now have two instances of NSMutableString, one leaked.
If you:
myString = [[NSMutableString alloc] init];
otherString = myString;
You now have a single instance of NSMutableString with two references.
In all three allocations, the NSMutableString instance will have a +1 retain count and, thus, you must balance each with a single release or you'll leak.
Treating retain counts as an absolute count is a path to madness. Or, at best, the scope of usefulness of the absolute retain count is so limited that learning about it is not applicable to real world iOS programming.
This bears repeating:
The retainCount of an object is tricky business.
If you were to continue down this path, you should be aware of the following details:
retainCount can never return 0
messaging a dangling pointer is not guaranteed to crash
retain count cannot be known once you have passed an object through any system API due to implementation details
any subclass of any system class may have an unknown retain count due to implementation details
retain count never reflects whether or not an object is autoreleased
autoreleases is effectively thread specific while the retain count is thread global
some classes are implemented with singletons some of the time (NSString, certain values of NSNumber)
the implementation details change from platform to platform and release to release
attempting to swizzle retain/release/autorelease won't work as some classes don't actually use those methods to maintain the retain count (implementation detail, changes per platform/release, etc..)
If you are going to teach retain/release, you should be treating the retain count as a delta and focus entirely on "If you increase the RC, you must decrease it".
when you call myString = [[NSMutableString alloc] init];, you're not "calling alloc/init on it again". You're not calling a method on the same instance you had. You're allocating and initializing a new instance, a completely different object from the one you had before.
And if you're doing that with a variable that had an object that you retained, then yes, you are leaking it.
Try this.
NSString *myString = [[NSMutableString alloc] init];
NSLog(#"%d", [myString retainCount]); // "1"
for (int i = 1; i < 40; i++)
[myString retain];
NSLog(#"%d", [myString retainCount]); // "40"
NSString *backup = myString;
myString = [[NSMutableString alloc] init];
NSLog(#"%d", [myString retainCount]); // "1"
NSLog(#"%d", [backup retainCount]); // "40"
You see, you have a different object with a new retain count. Your original object still exists and still has the same retain count. Assignment changes the object a variable refers to. A variable doesn't have a retain count, an object does.
myString = someOtherString;
NSLog(#"%d", [myString retainCount]); // who knows?
With retained property:
self.iString = backup;
NSLog(#"%d", [self.iString retainCount]); // "41" - 1 more because property retained
NSString *newString = [[NSMutableString alloc] init];
NSLog(#"%d", [newString retainCount]); // "1"
self.iString = newString;
// 1 for alloc 1 for retain (in real code you should release newString next)
NSLog(#"%d", [self.iString retainCount]); // "2"
NSLog(#"%d", [backup retainCount]); // "40" - self.iString released it

Why does this cause a crash?

I have these two buttons hooked up to these two methods (they're nearly identical)
-(void)moveOneImageNewer{
int num = [numberOfImage intValue];
num--;
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
-(void)moveOneImageOlder{
int num = [numberOfImage intValue];
num++;
numberOfImage = [NSString stringWithFormat:#"%i",num];
//Load the image
[self loadImage];
}
If I hit either of them twice (or once each, basically if they get called a total of two times) I get an EXC_BAD_ACCESS. If I throw a retain on: numberOfImage = [[NSString stringWithFormat:#"%i",num]retain] it's fine though. Can someone explain why this is? I did an NSZombie on the instruments and traced it back to this stringWithFormat call. Thanks in advance!
+stringWithFormat: doesn't contain 'new', 'alloc', 'copy', or 'retain', so it should be expected that you have to retain the return value of it if you want the new NSString it creates to stick around.
Edited to include this handy link duskwuff kindly dug up: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH
If numberOfImage is a properly declared property, e.g.
#property (copy) NSString *numberOfImage;
and it was properly synthesized (in the #implementation section for the class):
#synthesize numberOfImage;
then you can do:
- (void) moveOneImageNewer
{
self.numberOfImage = [NSString stringWithFormat: #"%i", [self.numberOfImage intValue] - 1];
// Load the image
[self loadImage];
}
The property setter will take care of retaining the string and, if necessary, releasing the previous string.
FWIW, why on earth is numberOfImage a string? Why not a simple int?
numberOfImage is an instance variable or property of your class, right?
You are setting it to a stringWithFormat (which returns an auto-released NSString) without claiming ownership of that object (by calling retain).
If you do not retain it, it will get auto-released before the method is called again (and then the first line will fail, as it tries to access the previously set, now auto-released value).
Consider using properties, they have auto-generated memory management code (including releasing the old NSString when you set the new one).
You haven't retained the string object in "moveOneImageOlder", so that object gets autoreleased at the end of the event cycle and points to nothing. That's why you get the EXC_BAD_ACCESS next time you try to use it.
Use a retain to claim ownership of the NSString. Remember to release when you're done though (you can use properties to help you with this)
-(void)moveOneImageNewer{
int num = [numberOfImage intValue];
num--;
[numberOfImage release];
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
-(void)moveOneImageOlder{
int num = [numberOfImage intValue];
num++;
[numberOfImage release];
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
Add this in dealloc:
- (void)dealloc {
[numberOfImage release];
[super dealloc];
}
Well, the NSString class method "stringWithFormat" returns an autorelease NSString object if I'm right.
So the second call to your method would have numberOfImage pointing to nothing, as the autorelease NSString object it used to be pointing to has already been released and deallocated since you didn't retain it.
The part that is directly causing the crash is [numberOfImage intValue] when you call the method a second time, as you sending a message to an object (pointed to by numberOfImage) that no longer exist.

Simple problem with NSString

I have this userInputstring in the header that will be modified and used by multiple methods in the .m file
.h
NSString *userInputString;
-(void)main;
-(void)method1;
-(void)method2;
.m
-(void)main{
[self method1];
[self method2];
}
-(void)method1{
NSString *localString = #"something";
userInputString = localString;
//do something else with it
}
-(void)method2{
NSString *localString = [NSString stringWithFormat:#"%# insert something",userInputString];
userInputString = localString;
[someOtherMethod:userInputString];//Crash
}
but I kept getting memory leak problems. What's the proper way to set it up? Im new to objective c.
I don't know where or how to release
Right, you first need to familiarise yourself with the Cocoa Memory Management Rules.
In summary, if you obtain an object by alloc, a method containing "copy", a method starting with "new" or if you retain it, you need to release or autorelease.
Take method1:
-(void)method1{
userInputString = #"something";
}
userInputString was not obtained with alloc, new or copy, nor have you retained it. Therefore you do not own it so you must not release it. If you had done this:
userInputString = [#"foo" copy];
or this:
userInputString = [[NSString alloc] initWithString: #"foo"];
or this:
userInputString = [#"foo" retain];
you do own the string therefore you must release or autorelease it.
When you release it depends on its scope. If it's a local variable, you must release or autorelease it before the block it is declared in exits. If it is an instance variable, you must release it before the object it is in is deallocated. i.e. you must release it in the dealloc method for the object. In all cases, if you overwrite an object you own, you must release it first. So:
userInputString = [someOtherString copy]; // you own userInputString
// do some stuff
[userInputString release]; // you no longer own it
userInputString = [someOtherString retain];// overwrite the pointeer with something else
This is one of the reasons for adding getters and setters for instance variables. Every time you set a new value, you have to release the old value and retain the new value (making sure that the old bvalue and new value are different), so this is encapsulated in the setter. A synthesized property adds this code automatically.
Try to use autorelease pool:
int main()
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
....
// Your code here
[pool drain]
return 0;
}
#"blablabl" is a shorthand to create an autoreleased NSString from a constant string. If if you don't have an autorelease pool in the thread you are running, those NSString object won't ever be released and of course your create a leak.
Either create an autorelease pool as Sumai suggest or release those objet's memory yourself. (tip: create an NSAutorelesePool ;-) )

Release in iPhone

Whenever I read about how to avoid memory leaks, I always came across a concept that
"Number of alloc must be equal to number of release".
But I came across a concept where we require more than one release. Like What I used to practise was as follows:
(NSString*) func1
{
NSString* result = [[NSString alloc] initWithFormat:#"Test String"]];
return result;
}
(void) func2
{
NSString* temp = [self func1];
[temp release];
}
But I came across a concept of retain count which says that in the above case the memory is not deallocated for the string since the retain count for the string is 1 at the end. So the right practise is
(NSString*) func1
{
NSString* result = [[NSString alloc] initWithFormat:#"Test String"]];
[result autorelease];
return result;
}
(void) func2
{
NSString* temp = [self func1];
[temp release];
}
So now I have two releases for deallocating the memory which is a contradictory to my above sentence which I read on most of the blogs ""Number of alloc must be equal to number of release".
I am little bit confused about the above stuff. Becoz if I autorelease the string in the first function and want to use the string in second function for a long time, and what if the release pool is flushed in between, on the other side if I dont use autorelease it will still block the memory.
So whats the correct way of doing it.
At the time you call alloc whatever is returned will have a retainCount of 1. Calling release on that object will cause it to be deallocated (it's retainCount will drop to 0). In your first example, then, the second line of func2 will deallocate the NSString* you received from func1, and your memory management chores are complete.
In the second example you are tossing result in func1 into the current autorelease pool, which will cause it to become deallocated when the pool drains. You do not want to attempt to manage the memory of that object once it has been placed into the pool- it is no longer your responsibility.
If you want to generate the string and keep it around for a while (e.g., through the lifetime of several autorelease pools), I would recommend the first form of memory management.
The correct way is this:
(NSString*) func1 {
NSString* result = [[NSString alloc] initWithFormat:#"Test String"];
// retaincount == 1
return [result autorelease];
}
(void) func2 {
NSString* temp = [self func1];
// retaincount == 1
// temp is autoreleased, therefore no [release] is necessary.
}
Autorelease is automatically done at the end of the run loop, that means it cannot be emptied while your code is doing something. -> The code you have is safe. This isn't true for multithreaded application!
(NSString*) func1
{
NSString* result = [[NSString alloc] initWithFormat:#"Test String"]];
return result;
}
[result retainCount] is 1
(void) func2
{
NSString* temp = [self func1];
[temp release];
}
[temp retainCount] is 0
No need for autorelease.
From Memory Management Rules:
This is the fundamental rule:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
The following rules derive from the fundamental rule, or cope with edge cases:
As a corollary of the fundamental rule, if you need to store a received object as a property in an instance variable, you must retain or copy it. (This is not true for weak references, described at “Weak References to Objects,” but these are typically rare.)
A received object is normally guaranteed to remain valid within the method it was received in (exceptions include multithreaded applications and some Distributed Objects situations, although you must also take care if you modify the object from which you received the object). That method may also safely return the object to its invoker.
Use retain in combination with release or autorelease when needed to prevent an object from being invalidated as a normal side-effect of a message (see “Validity of Shared Objects”).
autorelease just means “send a release message later” (for some definition of later—see “Autorelease Pools”).
In general, I'd feel safer to do a retain on a return value, like the one in the "func 2":
(NSString*) func1 {
NSString* result = [[NSString alloc] initWithFormat:#"Test String"];
return [result autorelease];
}
(void) func2 {
NSString* temp = [[self func1] retain];
// Do something with temp
[temp release];
}
Is this unnecessary? I understand that in this example "temp" is just a local variable. But it could have been an instance variable, which may need to be retained.