Correct Memory Management for [string UTF8String] - iphone

I'm somewhat new to objective-c and I'm not sure what the correct memory management for this code is.
const unsigned char * data =(const unsigned char *) [string UTF8String];
When I call free on data I get an error. Do I need to clean up after this call?

No. "UTF8String" does not contain the words alloc, copy, retain, or create. Thus, you're not responsible for that memory.
Note that if you want that data to stick around after string is released, you should copy it; by the contract, you're not responsible for that memory, but you are also not guaranteed that it will last beyond the scope of the object that gave it to you.

You do not need to free it.
In Cocoa, if a method does not contain the words alloc, init, or copy, you do not own the object that is returned from said method.
-UTF8String actually points to the cstring representation of the NSString object you are calling it on. When the object's state changes, the UTF8String also changes.

As stated in the documentation, it is automatically freed the same way an autoreleased object would be.

technically speaking, free() is used to remove memory allocated using malloc() from the heap.
malloc() was not used to allocate the memory. remember that objective-c is c with extensions.
the data variable will remain in memory based on the c language 'scoping' rules.

Related

Directly use of NSString

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.

releasing variables to save memory

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

What's the recommended approach for allocating an object in an instance methode, which will later on be returned?

For example look at the following example:
Code1
-(NSString*)getString{
return [[[NSString alloc] initWithFormat:#"test"] autorelease];
}
-(void)printTestString{
NSString *testStr = self.getString;
[testStr retain]
NSLog(#"%#",testStr);
[testStr release]
}
Code2
-(NSString*)getString{
return [[NSString alloc] initWithFormat:#"test"];
}
-(void)printTestString{
NSString *testStr = self.getString;
NSLog(#"%#",testStr);
[testStr release];
}
Code 1 and Code 2 should be valid Code Snippets and no leaks should appear.
Code 1 uses autorelease so the return variable has to be retained in printTestString and after using it released. So there is a small Overhead here because of autorelease.
Code 2 doesn't release the NSString in getString so you have to only release it after using it. Seems your have to write less and you dont have overhead because no autorelease is used.
Which one is the de facto "standard" approach that is used out there?
Another thing I was asking myself. Could the autorelease in getString and the retain with
[testStr retain]
be a problem, when the autorelease pool releases the variable right after
NSString *testStr = self.getString;
then the string would be gone. Is that possible or does the compiler prevent that sort of thing?
Thanks
-Sebo
Do this:
-(NSString*)getString{
return [[[NSString alloc] initWithFormat:#"test"] autorelease];
}
-(void)printTestString{
NSString *testStr = self.getString;
NSLog(#"%#",testStr);
}
Your getString method autoreleases the NSString, which means printTestString doesn't need to retain or release it. Autoreleasing in getString makes sense, because it alloced the object and is therefore the 'owner' of the object. I suggest studying Objective-C's memory management rules before proceeding, as they are very important.
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH
Jake's answer is correct for almost all of the situations you'll need to return an object from a method, but there are cases where you might want to return something that isn't autoreleased. From the Memory Management Programming Guide (Mac version, but they're the same rules):
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.
Also, from the Coding Guidelines for Cocoa:
In your methods and functions that
return object values, make sure that
you return these values autoreleased
unless they are object-creation or
object-copy methods (new, alloc, copy
and their variants). “Autoreleased” in
this context does not necessarily mean
the object has to be explicitly
autoreleased—that is, sending
autorelease to the object just before
returning it. In a general sense, it
simply means the return value is not
freed by the caller.
For performance reasons, it’s
advisable to avoid autoreleasing
objects in method implementations
whenever you can, especially with code
that might be executed frequently
within a short period; an example of
such code would be a loop with unknown
and potentially high loop count.
Therefore, methods containing the prefix alloc or new, or those that contain the word copy by convention will have you returning objects that are not autoreleased. In fact, the Clang Static Analyzer understands this convention and will assume non-autoreleased objects being returned from methods that follow these naming rules.
I've used the new prefix in situations where I preferred not to return autoreleased objects (tight loops where I didn't want to manage an autorelease pool, etc.). Again, returning autoreleased objects is what's recommended in almost all cases, but there are some times where you might want to avoid that.

iOS Memory Management: ivars, static, and NSStrings

I have managed to get myself confused about some elements of memory management. I am new to objective-c, and memory managed languages generally.
I have read the memory management guidelines, but I remain confused about a couple of things.
1) Is there any need to clean up ivars, and method variables that are not retained by any object. For instance
-(void) someMethod{
int count = 100;
for (int i=0; i <count; i++) {
NSLog(#"Count = %d", i);
}
}
What happens to the "count" var after the method is complete?
If a method allocates lots of temporary variables, do those get removed from memory as long as they are not unreleased, alloc'd objects? Or do i need to set them to nil in some way?
2) If i have a static variable, for instance an NSString, do I have to do anything for that to be removed from memory when the class is dealloced?
3) I have noticed that NSStrings seem to have a retainCount of 2147483647 which wikipedia tells me is the max value for a 32 bit signed integer.
http://en.wikipedia.org/wiki/2147483647
myString retainCount = 2147483647
-(void) someMethod{
NSString *myString = #"testString";
NSLog(#"myString retainCount = %d", [myString retainCount]);
// logs: myString retainCount = 2147483647
}
What happens to this at the end of the method? Does this memory ever get emptied? The string is not being referenced by anything. My understanding is that the #"" convenience method for NSString returns an autoreleased object, but whats the point of autoreleasing something with a retainCount of 2147483647 anyway? In that case, whats the point of retaining or releasing ANY NSString?
I am well aware that retainCount should be ignored, but it just bugs me not to know what's going on here.
4) Does this matter at all? I know that the memory associated with an NSString isn't much to write home about, but I want to be a good memory management citizen, and I'm more interested in best practices than anything else.
Retain/release only matters for objects, not int, bool, float, double or other built-ins. So use it for id or other classes that you hold a pointer to an object. In your example, count doesn't need to be retained or released. It is allocated on the stack which is automatically cleaned up when the function returns.
You do need to deal with any local objects you alloc. Those are created with a retainCount set to 1, so you need to either hold on to them for later or release them. Most Cocoa functions (that don't start with copy or alloc) return an object that is autoreleased. This means that they will have release called on them later -- you can only hold these after the function if you call retain on them. If you want them to be cleaned up, you don't need to do anything (calling release would result in too many release calls).
If you have a static variable pointing to an object, then it is not touched when objects of that class are dealloced. If you want it to be released, you have to call release on it. If the static is an int, bool, or other built-in, you don't (can't) call release on it. That's part of the global memory of your app.
NSStrings that are set to string literals should not have release called on them. The retainCount is meaningless for them. That value is also -1 for signed int values.
If you do this -- [[NSString alloc] initCallHere:etc] -- you have to call release on it. Most of the time you get strings, you don't use alloc, so you don't need to call release. If you retain one, you need to call release.
Yes, it does matter. Over time leaks will cause the iPhone to kill your app.
You don't need to worry about count cause it's an integer, a primitive data type, not an object.
I've read that those just go away upon app termination or if you explicitly release them.
You are right in that you should not worry about the retain count in that way. Cocoa automatically gives #"" (NSConstantString objects) the absolute highest retain value so that they cannot be de-allocated.
You are over complicating the subject. The point of the three guidelines is so that you know that you only have to worry about memory management in three specific situations. Apple gives you these guidelines so that one doesn't have to worry about the specific internals for every single class (like manually tracking retainCount), not to mention that sometimes Cocoa does things differently (as with NSConstantString). As long as you remember these guidelines, you really don't have to know the very gritty details of what's going on underneath (of course, an understanding of the retain count concept helps, but compare this to manually tracking it).
I don't know which guide you read specifically, but if you haven't given this one a try, I highly recommend it. It summarizes the three guidelines in a concise and direct manner.
The Cocoa memory management rules only cover Objective C objects.
Local variables (non-static) are cleaned up when any subroutine or method exits (actually the stack memory is just reused/overwritten by subsequent subroutines or methods in the same thread). Constants which require memory (strings) and static variables are cleaned up when the app is torn down by the OS after it exits. Manually malloc'd memory is cleaned up when you manually free it.
But any object you alloc or retain: (whether assigned to an ivar, local, global, static, etc.) has to managed like any other object. Be careful assigning objects to global variables, unless you are really good at retain count management.

NSString to C-style char array crashes on second invoke to drawRect

I am trying to write text using a Core Graphics context. I can do it the first time, no problem, but the second time crashes my iPhone app. Here is a code snippet:
NSString *name = [MyClass getName];
const char *cname = [name UTF8String];
[self drawText:context text:cname];
MyClass and drawText are custom classes/methods but you get the idea. These three lines live in drawRect:
The first time drawRect: is executed, I see the text as expected. However, on any refresh of drawRect:, the line:
const char *cname = [name UTF8String];
causes my app to crash with the cryptic, "GDB: Program loaded." status message.
I get a similar response even when I use the getCString: method. I think I might be missing a fundamental understanding of NSString to char array conversion.
It sounds like you're trying to call methods on an object which has been deallocated already. The UTF8String message has the problem that you can't hold onto the returned pointer, since it may become invalidated when the string is released -- you have to copy the string if you need to hold onto it. However, getCString:maxLength:encoding: does not have that problem.
Make sure you're following properly memory management protocol. See the Memory Management Programming Guide for Cocoa, and double-check that you're sending retain, release, and autorelease messages to the proper objects at the proper times. Chances are you're sending an extra release or autorelease when you shouldn't be, or you're forgetting to retain your string somewhere.
The most likely cause is that you're keeping a reference to the previously returned char* and you are dereferencing it on the second call. According to spec, the pointer is not valid to store: The returned C string is automatically freed just as a returned object would be released; you should copy the C string if it needs to store it outside of the autorelease context in which the C string is created.