I'm a first time Objective C programmer. I've been reading other people's code and I often see static strings created but never released. Take this for example:
- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSSSTring* foo = #"foo";
// [code to return a cell for the table]
}
To my understanding, space for 3 characters in the heap has been allocated to store the string "foo". When the program terminates, those 3 characters are never reclaimed because the author never releases them. Isn't there a memory leak here? Why or why not?
Actually, constant strings like #"foo" are treated specially by the compiler. In particular, they are not heap allocated, and they do not participate in reference counting, i.e., they are never actually released; their memory is part of your program's image, just like the content of, say, "foo". However, this should be treated as implementation detail of this particular kind of NSString subclass. Follow the usual rules for reference retention/release.
Related
This question already has answers here:
Do I need to release a constant NSString?
(2 answers)
Closed 10 years ago.
In my research I've come across something peculiar.
#interface Class {
NSString *_string
}
- (void) Method1 {
_string = #"ASDF";
}
Intially I thought that _string was part of the autorelease pools and really didn't think about the memory aspect of it.
After reading this SO post Objective C NSString* property retain count oddity
I've realized that no, this is not the case, and that the retain count of _string is actually UINT_MAX
Obviously my thinking that _string was part of the autorelease pool was a fluke, and how I handled the variable just somehow worked out. What I would like to know, though, is: when does #"ASDF" get thrown away? I know I should be using properties and setters, but there is probably a lot of code out there that looks like this since assigning a constant to a variable is so intuitive.
What is the lifecycle of these immutable, literal NSStrings, and when will [_string length] actually return an error since #"ASDF" doesn't reside in memory anymore?
From Is a literal NSString autoreleased or does it need to be released?
Compiler allocated strings (of the format #"STRING") are constant, and
so -retain, -release, and -autorelease messages to them are ignored.
You don't have to release or autorelease foo in this case (but it
won't hurt).
Under the hood when you do
NSString* yourString = #"ABC";
the string will be stored in a area of memory called data segment. This area never changes after the application is launched. Here strings are treated as constants for your app. At the same time a string is an object, so if you want to keep it you call retain or copy.
On the contary when you do
NSString* yourString = // alloc-init
you create an object on the heap. If you forget to release you have a memory leak. If someone else destroy it, and you try to access it, you have a bad access to that memory location.
Hope that helps.
An immutable string (NSString) that is created manually follows the normal reference counting rules and thus life cycle.
In your example, the string is even more special because it is actually a string literal. As is the case for any literal, they reside in special memory and only get destroyed when the executable terminates.
In programming there is a general rule introduced by Kernighan & Ritchie saying that you have call a "free" for all space allocated by a "malloc".
So the following code is correct:
- (UIImage*) convertImage:(UIImage*)sourceImage {
unsigned char *rawData = malloc(requiredSpace);
...
...
free(rawData);
return imageRef;
}
However you also have encapsulation within a function. So after the return from the function, the memory will be automatically freed. So theoretically the free is not absolutely required in the above example. Is this correct?
Absolutely no.
The free is necessary since the memory will be freed only for statically allocated variables. If you use malloc (as well as calloc or realloc) you are dynamically allocating memory that will not be freed except if you explicitly call free.
For example:
-(void)method {
char a[10];
char *b = (char*) malloc(10*sizeof(char));
}
a will be destroyed at the end of the scope (at least, will be marked as free memory, so that you cannot rely anymore on its content), while b remains in memory until the end of the program. If you lose the pointer to that memory address (maybe assigning another value to b or simply ending the function without returning b), you will not be able to free the memory anymore, and this will bring to a memory leak.
I'm working on a project that has C code embedded within Objective-C code. The C code produces some void * pointers that I would like to pass between Objective-C methods, so I'd like to wrap them in Objective-C objects to make an NSSet or something to that effect.
I have looked into NSData, which seems to accept arbitrary data, but wants to know the length of the memory chunk, that I don't have.
Any help is appreciated.
The NSValue class is usually used for this task:
NSValue* value = [NSValue valueWithPointer: myPointer];
and
void* myPointer = [value pointerValue];
Note, though, that the pointer given will not receive any special treatment with respect to memory management. You (and you alone) are responsible for making sure, that the memory it points to remains valid as long as pointers to that memory region exist and are reachable in some part of your program.
Note, though, that using such a value with NSSet or as key in a NSDictionary might or might not yield the intended effect:
NSData is essentially a byte buffer. It actually represents the content of the memory in question. Comparing NSData instances for equality compares at byte level. This is one of the reasons, NSData needs to know about the length of the memory region in question.
NSValue with a pointer value is an entirely different beast. Here, that actual (numeric) pointer value is the essential thing. No consideration is given (when comparing two NSValue instances) to the actual content at the address.
I am somewhat confused about memory allocation of static variable in objective C.
should we allocate memory for static variable using alloc:? and
initialize it usinginit:?
Is objective c static variable same as c static variable?
is it worth to apply retain on static variable?
There are a couple of things you need to take into account.
First, static C-like variables inside functions are technically fine. This should be:
- (void) f
{
static NSString* s = nil;
if (s == nil) {
s = [[NSString alloc] initWithString:#"Hello"];
}
}
The problem is that you will probably never be able to release, since s scope is only f function.
This is exactly like a C static variable inside a function.
There is also static usage to control visibility of a variable in a translation unit. So, if you want to only allow some variable to be accessed within file.c, just like C, you need to write in that file:
static NSString *s = [[NSString alloc] initWithString:#"Hello"];
Again, unless you write a specific method to release when you application ends, it will probably leak memory.
Finally, you can have "object oriented like" static behavior. You don't use static keyword here but as most object oriented languages, you can have class variables (in Java, C#, C++ and others, class variables are accomplished with the static keyword).
I only have answers to the first two of your questions — because I don't understand what you mean by your third one.
Let me start with question 2.:
Is objective c static variable same as c static variable?
Objective C (ObjC) is, basically, just plain-old-C (POC) — and a nifty dynamic runtime, that adds a lot of fancy.
This means that every C language qualifier (e.g. static) works in ObjC exactly like it would in POC.
So the answer to that question is: yes.
With that cleared, back to number one:
should we allocate memory for static variable using alloc:? and initialize it usinginit:?
The important thing about ObjC you need to always be aware of is, that there are no stack objects:
Every object you'll ever use lives on the heap.
From that follows that it is irrelevant in which scope (be it stack-local, static or global) you declare your object-type variables, in general, they will always be effectively alloc/inited.
There is one exception to these rules:
Blocks at least start out as stack variables — but those are funny creatures, anyway.
So, to answer this question: You actually don't have a choice!
Aside
if you're using statics for objects other than literal NSStrings — which might well be totally reasonable — consider wrapping them with a proper class-method, for sanity's sake.
This is a nice way of doing it:
+ (NSNumber *)theMagicNumber
{
static NSNumber *magicNumber;
static dispatch_once_t numberSemaphore;
dispatch_once( &numberSemaphore, ^{
magicNumber = [NSNumber numberWithInt:3]; // 1
[magicNumber retain]; // 2
} );
return magicNumber;
}
Notes:
As you probably know +[NSNumber numberWithInt:] returns an autoreleased object!
Since we want to hold on to this object, we need to retain it, as usual — or compile our code using ARC and get rid of lines like this, altogether!
I hope this example answers or at least helps you figuring out the answer to your last question.
I know all instances of NSString are inmutable. If you assign a new value to a string new memory is addressed and the old string will be lost.
But if you use NSMutableString the string will always keep his same address in memory, no matter what you do.
I wonder how this exactly works. With methods like replaceCharactersInRange I can even add more characters to a string so I need more memory for my string. What happens to the objects in memory that follow the string? Are they all relocated and put somewhere else in memory? I don't think so. But what is really going on?
I know all instances of NSString are
inmutable. If you assign a new value
to a string new memory is addressed
and the old string will be lost.
That isn't how mutability works, nor how references to NSStrings work. Nor how pointers work.
A pointer to an object -- NSString *a; declares a variable a that is a pointer to an object -- merely holds the address in memory of the object. The actual object is [generally] an allocation on the heap of memory that contains the actual object itself.
In those terms, there is really no difference at runtime between:
NSString *a;
NSMutableString *b;
Both are references to -- addresses of -- some allocation in memory. The only difference is during compile time, b will be treated differently than a and the compiler will not complain if, say, you use NSMutableString methods when calling b (but would when calling a).
As far as how NSMutableString works, it contains a buffer (or several buffers -- implementation detail) internally that contain the string data. When you call one of the methods that mutate the string's contents, the mutable string will re-allocate its internal storage as necessary to contain the new data.
Objects do not move in memory. Once allocated, an allocation will never move -- the address of the object or allocation will never change. The only semi-exception is when you use something like realloc() which might return a different address. However, that is really just a sequence of free(); malloc(); memcpy();.
I'd suggest you revisit the Objective-C Programming Guide or, possibly, a C programming manual.
the NSMutableString works just like the C++ std::string do. i don't know exactly how they work, but there are two popular approaches:
concating
you create a struct with two variables. one char and one pointer.
when a new char(or more are added) you create a new instance of the struct, and add the address to the last struct instance of the string. this way you have a bunch of structs with a pointer directing to the next struct.
copy & add
the way most newbies will go. not the worst, but maybe the slowest.
you save a "normal" unmutable string. if a new char is added, you allocate a area in the memory with the size of the old string +1, copy the old string and concate the new char. that's a very simple approach, isn't it?
a bit more advanced version would be to create the new string with a size +50, and just add the chars and a new null at the end, don't forget the to overwrite the old null. this way it's more efficient for string with a lot of changes.
as i said before, i don't know how std::string or NSMutableString approaches this issue. but these are the most common ways.