In the code below, will tapsLable.text be deallocated when tapsMessage is released or does the assignment operator somehow increment the retain count so that tapsLabel.text continues to be available?
NSString *tapsMessage = [[NSString alloc] initWithFormat:#"%d taps detected", numTaps];
tapsLabel.text = tapsMessage; // tapsLabel is a UILabel object
[tapsMessage release];
Here's a tip
You can write the retainCounter for the object then you see what it is before and after the assignment.
e.g. NSLog( #"%d", [tapsMessage retainCount] );
That way you can answer such questions in the future by just writing out the retainCount as it always depends on how the property is declared.
tabsLabel.text is a property on tapsLabel. I think it's a string property that does [target copy] on assignment. Nevermind the details, yes, the assignment operator either increments the retain count or copies the value, so you can release tapsMessage and it is still available in tapsLabel.text.
Read more about properties here.
EDIT: looked up UILabel in the header, yes, it does a copy for the text property.
#property(nonatomic,copy) NSString *text; // default is nil
EDIT: to expand on the important question in the comment
How does anyone know when to release and when not to if you have to look at the implementation details of every object you assign something to?
You just follow the memory management rules. The point of the refcounted environment is exactly that there is some "loose coupling" going on between the objects in terms of memory management. As long as you retain and release properly, it is not your concern whether someone else also retains and releases these same objects, as long as all involved parties have their retains/releases matched.
In the first line, you have allocated and initialised an NSString. You own this object according to the memory management rules, which means you are responsible for releasing it.
In the second line, you are assigning the tapsMessage string the text property. This property (assuming tapsLabel is a UILabel) is declared with the copy attribute. For immutable strings (NSStrings), asking for a copy simply increments the retain count, since there is no need to make an actual duplicate of the data (the data can never change). Since UILabel has made a copy of the string, it has claimed ownership as well (objects can have more than one owner).
In the third line, you relinquish your ownership but the string still has one owner (the label), so the object is not deallocated.
It will not be deallocated.
Related
I find I usually directly use a NSString like:
self.text = #"word";
label.text = #"word";
function(#"word");
I think it is a wrong way to directly use NSString, because the #"word" will have a retainCount of 2 after it has been used. Is that right?
What is exactly the retainCount of #"" ? Is it an autorelease object or has a retain of 1?
What`s more, I encountered some memory leak as the pic shown below:
I suspect it is related to the direct use of the NSString.
Essentially, the retain count of NSString literals is infinite. The memory for these objects is reserved by the compiler at compile time and never gets released for the duration that your app is running, no matter how often you try to retain or release them.
This is another good example why it is wrong to care about retain counts. You should only care about the golden memory management rules: if you take ownership of an object (with alloc, new, copy or retain), you have to release or autorelease it later. Otherwise, you don't.
Quoting from String programming guide
The simplest way to create a string object in source code is to use the Objective-C #"..." construct:
NSString *temp = #"/tmp/scratch";
Note that, when creating a string constant in this fashion, you should avoid using anything but 7-bit ASCII characters. Such an object is created at compile time and exists throughout your program’s execution. The compiler makes such object constants unique on a per-module basis, and they’re never deallocated, though you can retain and release them as you do any other object.
the #"word" will have a retainCount of 2 after it has been used. Is that right?
No. This is a perfect illustration of why it is bad to think in terms of retain counts which are an internal implementation detail. You can think of string literals as strings that are "owned" by the executable image so they will not go away. You should treat them like any other Objective-C object.
If you do take a sneaky peek at the retain count of a string literal, you'll find it is set to some really big number (something like the maximum value for an NSInteger). This is treated as a special value by retain and release that they don't change.
The memory for string literals is allocated as part of the binary image at compile time. It can never go away. Your memory leak is not because of this.
No, it's a good thing to declare an autoreleased NSString by using directly #"". But NSString are retained in a particular way and it's not really possible to know what's being done at runtime. You may have weird retain count sometimes. Don't bother about your leak of 48 Bytes.... It's not related to your nsstring.
I have a beginner's question about releasing variables and not wasting memory...
I don't quite understand when to release variables. I understand that I should always do this if I have assigned them in my header file (in my #interface section and my #property commands). I release them in my -(void)dealloc function.
However, what am I supposed to do with variables that I happen to use in some of my methods, e.g.:
for (int temp = 0; temp < 3; temp++) {
// do something...
}
[temp release];
This is obviously wrong (at least xCode tells me so), as 'temp' is undeclared. But why? I've declared it as an int and temp thus takes up space in my memory, I'm sure. How do I tell the program to free up the space temp has taken after I don't need it anymore? I'm sure this is obvious, but I simply don't get it.
I'd be very happy for any suggestions for a beginner of how not to be a memory pig and to have 'memory leaking' everywhere in my apps...
You declared it as an int in the scope of the loop. Once the loop is done, it goes out of scope.
Also, you can not release an int, which is a primitive type. You can only release a subclass of NSObject. A good rule of thumb is that you eventually have to release anything that you called alloc or retain on.
Edit: For your edification, memory management only applies to objects allocated from the heap. That would be NSObjects obtained via "alloc" or must C-level memory allocated with something like "malloc()". Declaring a variable like "int x" is called an "auto" variable in that is is created on the stack and will AUTOmatically disappear then that block ends (the end of a "block" being the end of the function or perhaps the end of a {} pair or even the end of a for/if/while block.
Since Objective-C is basically just a special version of C (with messages), it does not create permanent objects unless you explicitly tell it to. This is different form languages like Python or Javascript.
You only need to release objects, and temp is an int, not an object.
As far as when to release objects, Apple's docs explain that better than I can: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
You do only release objects, and not primitive types. For example you create an array with
NSArray *myArray = [[NSArray alloc] init];
This initialization allocated memory which you have to free after your done using your array, it's your responsibility, else there will be memory leaks. You can do that in the dealloc section of a controller, or at the end of a method, or even after you've enumerated through the array and no longer need it.
If you create instances of objects with other methods than alloc, copy or new(rarely used) you have to release them. If you call retain yourself on an object you have to release it as well.
Please refer to apples memory management rules, which have been posted earlier.
There are two ways to store information in RAM in C and c like things, primitives which are allocated automatically by the compiler, and memory chunks allocated by you in your program.
Variables allocated for you by the compiler are called "automatics" and can be marked by the essentially unused (because it is the default) "auto" keyword. Automatics are bound to the scope in which they are declared and go away when it ends. Regular variables, like "int x" are automatic.
Notably, pointers are typically automatic. However, the things they point to are not. Those would be the thing you asked to be allocated.
In objective-c, things are allocated with the alloc message. However, sometimes a class will call this for you, so you might not see it. To help make it clear what you should do, there is a tradition: If you get an object where you alloc'ed it, got it from a class method with the word "copy" in the method name, or sent it a "retain" message, then you own a share of it, and it won't go away until you send it a release message.
If you didn't get the object through one of those means, you must not release it, because you don't have a share in it.
So, in summary: regular variables (int, short, char, double, float, long) are automatic, no need to allocate it. Pointers are also automatic, however, the things they are pointing to are not. In obj-c, you own a share if you alloc'ed it, copy'ed it, or sent it a retain message.
You can't release an integer...
Release works only with instance of Objective-C classes.
Variables such as integers are placed on the stack, and they does not persist after a function/method call, unless allocated explicitely.
You only release objects. If you use the alloc, init procedure to create an object you must release it. If you retain an object you must release it. If you use a method that has the word "create" in it, you must release it. Anything else, the system will handle for you.
Primitives do not need to be released, only objects.
Biggest thing to keep in mind is that whenever you "alloc" or "retain" an object, put a corresponding "release" or "autorelease".
you see an error on the line [temp release]; because temp is not in scope. temp will not be seen outside of the for loop you created.
you do not need to clean up the memory of temp, since you have not claimed ownership of it(see Memory Management Rules): http://developer.apple.com/library/ios/#documentation/general/conceptual/DevPedia-CocoaCore/MemoryManagement.html
examples of objects where you do not need to release/manage memory:
NSArray *myArray = [NSArray array];
NSNumber *myNumber = [NSNumber numberWithInt:5];
NSString *myString = #"Hello World";
NSInteger i = 5;
int x = 2;
examples of objects where you do need to release/manage memory:
NSArray *myArray = [[NSArray alloc] initWithObjects:#"Hello", #"World", nil];
NSNumber *myNumber = [[NSNumber alloc] initWithInt:5];
NSString *myString = [[NSString alloc] initWithString:#"Hello World"];
-
typically, when your completely done using an object you own, you clean up its memory
see apple's docs for explanations on properties: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW1
setting a property with assign or readonly: you should not worry about releasing its memory, as you don't own it
property with retain or copy: you claim ownership of the object and need to release it at some point
this answer won't answer/solve all memory management questions/concerns, but it may shove you in the right direction
I have a question about a retain and a NSString, if I have a method who a return a NSString, and I put the return NSString in a nsstring variable, I must do a retain or not?
NSString *myString = #"";
myString = [self methodWhoReturnString]; // I must do this?
myString = [[self methodWhoReturnString]retain]; // Or I must do this?
The Apple Developer Documentation on Memory Management explains the scenarios where you retain/release objects.
Simply put, if you want the string to stick around, you need to retain it until you're finished with it. If that is just the scope of the current function, you can get away without retaining it as if the string is already autorelease'd (likely) it won't get released until your function finishes and the current AutoReleasePool is purged.
Bear in mind that an NSString * could actually be pointing to an NSMutableString *. If it matters to you if the string is changed by some other function without you realizing, be sure to copy it: NSString * myCopyOfString = [mystring copy];
If the string is set to autorelease, which it most likely is, then yes you will need to retain it somehow. I would suggest doing this though:
myString = [[self methodWhoReturnString] copy];
this ensures you have retained the data in the string not just a reference to a string that might still be controlled elsewhere. Be sure you release your copy later!
Usually, methodWhoReturnString would return an autoreleased string, which means you should retain it if you want to keep it around.
So, if methodWhoReturnString is your method, I believe that to keep with convention you should return [stringToReturn autorelease]; from that method, and then retain it if you want to keep it.
You use retain if you're going to be using myString at a later point in time (i.e. after the current method has returned) to prevent it being autoreleased.
You don't need to use retain if it's just a temporary variable used within the current method, since in that case you do want it to be autoreleased.
One special case is properties. If you call self.blah = foo, you don't need to retain foo, since the setBlah: method should do it for you.
(there's a whole load of other complexities and edge cases, but this is a good rule of thumb to get you started on understanding what to do)
Given the code you provided, you shouldn't call -retain. In your example, the return value of a method that returns an instance of NSString is assigned to myString, an automatic local variable. If the assignment had been made to an instance variable or a static variable, you would want to call either retain or copy to guarantee that the reference remains valid beyond the end of the local scope.
In this case though, the reference to the NSString instance is stored in a variable that will be destroyed automatically at the end of the local scope, so your code needn't concern itself with the object's lifetime.
Any method that has alloc, new or copy in it automatically retains and infers that you have ownership of the object. All others shouldn't. It would be helpful if you had more context though. If we are in a contained method where this string is used briefly, then you probably don't need to retain. If it is going to be used for a while, you might want to use the #synthesize syntax to make it a property of the class you are in. When you use #property and #synthesize and call something like self.myProperty = something it will automatically retain.
As everyone knows, setTitle automatically retains the string passed as a parameter. When the button caption needs to be changed, I guess that it is necesary to release the current (old) string before setting the new one. I wonder what is the most elegant way to dot it.
See my code sample (here, getPlayerHandFromGame method produces autoreleased strings which are retained when setTitle is invoked):
colourString = [pGame getPlayerHandFromGame:1 withColour:COLOUR_HEARTS];
// Split colourString into array of strings if not null.
if ([colourString length] != 0) {
listCards = [colourString componentsSeparatedByString:#" "];
for (cardCounterSameColour = 1; cardCounterSameColour <= [listCards count]; cardCounterSameColour ++) {
currentCardButton = [self buttonCardNumber:cardCounter];
// Objects are numbered from 0 in the array
[currentCardButton setTitle:[listCards objectAtIndex:cardCounterSameColour-1] forState:UIControlStateNormal];
cardCounter ++;
}
}
This portion of code will be called several times since the button caption will be updated several times. I guess that before setting the title, I should do something like this:
[currentCardButton titleForState:UIControlStateNormal release]
in order to release the string which will not be used anymore (titleForState returns a pointer to the NSString).
Is that the right way to avoid that the device memory gets loaded with unused strings ?
Many thanks,
Apple92
Any class that retains a value set on one of its properties is also responsible for releasing the old value when that property's value gets changed again. Don't worry about it.
As everyone knows, setTitle automatically retains the string passed as a parameter.
Really? I don't know it. In fact, I'll bet a pint of beer that it doesn't retain the string, but copies it.
Granted, for an NSString, -copy is probably implemented as doing a retain and returning self, but if you pass it an NSMutableString, a genuine copy will occur.
I guess that it is necesary to release the current (old) string before setting the new one.
Guess again, sucker!
Or less facetiously: any object is responsible for managing the ownership of other objects it wantsa to keep hold of. Once you have passed the title in setTitle: you do not need to worry about how the object disposes of it once it gets a new one.
Consider the code:
[currentCardButton titleForState:UIControlStateNormal]
and apply the memory management rules to the return result.
Did you obtain it with alloc, new or copy? No. Did you retain it? No (remember we are talking about the object passed back by the method,not the object you originally gave it). Therefore, you must not release it.
Take a look at the object ownership convention:
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmObjectOwnership.html#//apple_ref/doc/uid/20000043-BEHDEDDB
Every class should follow these rules (Apple's does it), so in order to them you dont have to worry because you haven't done a alloc/retain in your class, and the button will retain it for it's internal use.
Currently I am jumping into the ice cold water called "memory management in iPhone OS".
Here's one rule i've learned:
Every time I see an alloc in my method, I will release that corresponding variable at the bottom of the method.
Every time I create an #property(...) in my header file which says copy or retain, I put a release message on that variable into the dealloc method.
Every time I have an IBOutlet, I do the same thing. Only exception: If the IBOutlet has something like #property(... assign), or in other words: If it has the assign keyword at all. Then I don't care about releasing it in the dealloc method.
I feel that there are many more good rules to know! Just write down what you have. Let's scrape them all together. Links to great descriptions are welcome, too.
Actually, any time you initialize an object and the method name includes "init" you are responsible for releasing it. If you create an object using a Class method that does not include the word "init" then you don't.
For example:
NSString *person = [NSString stringWithFormat:"My name is %#", name];
does not need a release. But:
Person *person = [[Person alloc] init];
needs a release (as you stated in your question). Likewise:
Person *person = [[Person alloc] initWithName:#"Matt"]];
also needs a release.
This is a convention, not a rule of the language, but you will find that it is true for all Apple-supplied APIs.
The rules I use
Release all objects you create using a method whose name begins "alloc" or "new" or contains "copy".
Release all objects you retain.
Do not release objects created using a +className convenience constructor. (The class creates it and is responsible for releasing it.)
Do not release objects you receive in other ways E.g.
mySprockets = [widget sprockets];
If you store an object you receive in an instance variable, retain it or copy it. (Unless it's a weak reference - just a pointer to another object, usually to avoid cyclical references.)
Received objects are valid within the method they are received in (generally) and are also valid if passed back to the invoker.
Some good links:
http://www.gehacktes.net/2009/02/iphone-programming-part-2-objective-c-memory-management/
http://mauvilasoftware.com/iphone_software_development/2008/01/iphone-memory-management-a-bri.html
Memory management can seem daunting when you're seeing segfaults spring from every seeming innocent line of code, but it's actually pretty easy once you get the hang of it. Spend a little time reading this page and then Apple's documentation, and you should be writing bug-free code in no time.
I tend to create only autoreleased objects, either by using a class method or by autoreleasing it immediately after creation, unless I can state a reason not to. For example:
I am assigning it to a member variable because I intend to hold onto it for a while.
I am only creating it to pass it on immediately to another method, and I send it a release message right after that method call.
For performance reasons, I need to free that memory before the nearest NSAutoreleasePool will be released, such as creating a large number of objects inside a loop or the objects are holding onto a large amount of data (e.g., images).
That way, I am less likely to leak objects. By default, I create them autoreleased, and when I make the deliberate decision not to autorelease them, I am immediately faced with the question of where they will be released.
For object properties, rather than releasing them in my dealloc method, I like to assign nil to them. That way, retained or copied properties are sent a release, while assigned properties are simply overwritten, and I don't have to update my dealloc method if I change the property to/from retained.