Is the const char* valid?
Does ARC keep track of the pointer returned by this function?
const char* getUrl()
{
// retrieve an url with obj-c
NSString *maybeTmp = [[NSString alloc] initWithString:#"some url"];
return [maybeTmp UTF8String];
}
This code is used as a bridge. A C library is going to call this function.
I would guess that ARC doesn't keep track of that pointer and will release this NSString once the function getUrl() returns, leaving the pointer as non valid.
Is the pointer non-valid after the end of the function?
If non-valid, is there a way to explicitly ask ARC to keep track of it?
No, ARC does not (and cannot) manage lifetimes of non-object types. If you take a look at the documentation for -[NSString UTF8String], you can also see the following:
This C string is a pointer to a structure inside the string object, which may have a lifetime shorter than the string object and will certainly not have a longer lifetime. Therefore, you should copy the C string if it needs to be stored outside of the memory context in which you use this property.
The UTF-8 string you get back has a maximum lifetime of the lifetime of the source NSString (which ARC will clean up at the end of the function), so if you need to hold on to the string, you'll need to make a copy using strdup or similar (and manage the lifetime yourself).
Is the pointer non-valid after the end of the function?
You are correct. ARC keeps track only of memory allocated to reference-counted objects. Sinc char* returned by UTF8String does not refer to a reference-counted object, ARC does not know of its existence.
If non-valid, is there a way to explicitly ask ARC to keep track of it?
No, because char* lacks "infrastructure" for keeping reference count. You could either return a reference-counted object which encloses your char*, or use malloc, make a copy, and let the caller free the string.
Related
How can I remove memory allocated by const char* arrayname in iOS 7.
here is my code
const char *bytes = [encodedString UTF8String];
Now I want to release bytes with ARC enabled. How can I do that.
You don't need to do anything to ensure it will be released eventually. Quoting the documentation:
The returned C string is a pointer to a structure inside the string object, which may have a lifetime shorter than the string object and will certainly not have a longer lifetime. Therefore, you should copy the C string if it needs to be stored outside of the memory context in which you called this method.
In other words, you don't know the lifetime of the array, but you know it may not live long and it will be freed automatically.
You should not release memory pointed by bytes pointer directly as it is managed by encodedString object. To free that memory get rid of all strong references to encodedString and memory should get released
As I understand pointers contain the address of data at another memory location?
When an app is running how is the location of pointers kept track of?
Why bother keeping track of the pointer, why not just directly keep track of address the pointer holds?
Additionally if I have the following code:
NSString *string = #"hello";
string = #"bye";
I am changing the value stored in the pointer named string (is it the pointer that is named string or the NSString object?) to the address of the new string ("bye"), right?
So how would I go about changing directly the object stored at the address held by the pointer?
(Also what is the correct terminology to use where I have used "keep track of"?)
Thanks
Why bother keeping track of the pointer, why not just directly keep
track of address the pointer holds?
Object references in objective C are actually pointers, so each time you use an object (such as NSString), you use a pointer to it - (NSString *)
I am changing the value stored in the pointer named string (is it the
pointer that is named string or the NSString object?) to the address
of the new string ("bye"), right?
Right.
So how would I go about changing directly the object stored at the
address held by the pointer?
In the case of such strings, they are immutable, and you can't change them, in case of other objects, you call their methods, or set their properties.
When an app is running how is the location of pointers kept track of?
Pointers are stored as any other variable; they typically take the same size as an unsigned long, but this is by no means guaranteed, just to give you an idea of how they are implemented. Compilers are free to do a huge variety of optimizations, so the pointers may be stored in memory, they may be stored in registers, or they may exist only as hypothetical entities if they are optimized away.
Consider the following code:
void foo(void) {
char *c;
char buf[100];
for (c=buf; c < buf+100; c++ {
c = '0';
}
}
In this case, the variable c is being used to write an ASCII 0 character to every character in the buf array. c may exist only in a register, because it does not live beyond this function. (There are better ways of writing this code.)
Consider the following code:
struct foo {
char name[10];
struct foo *next;
}
The member next in this case is a pointer to further struct foo objects -- say, a linked list of these things. These pointers must be stored in memory, because they are part of the contract of these objects -- they have to be there. There is no way around these pointers, either -- the objects they point to can be replaced with other objects on the programmer's whim. And, since the number of these objects is determined entirely at runtime, the compiler can't just keep track of the addresses in its symbol tables, as it would for stack-allocated variables.
So how would I go about changing directly the object stored at the address held by the pointer?
This is complicated by your example's use of "foo" strings in the code. These are saved in read-only memory in the process address space, so you cannot modify them. (Surprise!) If you initialize the strings with another method, you can modify the data via the pointer:
char *c = malloc(10);
strcpy(c, "hello");
c[0] = 'H';
printf("c: %s\n", c);
This will overwrite the h with H in the allocated space available via the c pointer. Accessing pointers as if they were arrays is the same re-writing the pointer access like this:
c[0] = 'f';
c+0 = 'f';
And, in fact, array accesses are pretty similar -- the name of the array is the same as a pointer to its first element.
It's a little complicated; the book Expert C Programming covers pointers in astonishing detail and is well worth the money.
Q : So how would I go about changing directly the object stored at the address held by the pointer?
Ans : start using NSMutableString if you want to change the content of memory location pointed by the your string pointer.
NSString is inmutable type ie you can't change the content but you can make the pointer to point somewhere else. "hello" to "bye" in your case.
According to the documentation for NSString's method -UTF8String:
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.
So under retain/release memory management, the following method:
- (const char*) giveMeACString
{
NSString* string = #"I'm a string!";
return [string UTF8String];
}
is fine, so long as the calling method treats the returned const char* as it would an autoreleased object.
However, under garbage collection there isn't an autorelease context, as far as I'm aware. And C types aren't garbage collected, so it doesn't look like the GC will treat the returned pointer as it would a returned object.
What is its lifespan tied to? Is it still freed at a point in the thread's runloop that is reliably `later on', or does it behave differently under GC than under non-GC?
I think the memory is allocated from garbage collected memory and the return type is __strong const char*. This means that it will be collected in the normal way when it is not reachable from the root set of pointers.
That basically means you need to store it in a pointer variable that is marked as __strong or it will be collected at some point.
I'd speculate that an immutable string maintains a reference to the UTF8 version of itself, so it only has to calculate it once and therefore the UTF8 string probably won't go away until the NSString does which is why you don't have to worry about it disappearing normally.
Since you did not explicitly allocate those spaces, you do not need to worry about deallocation.
I am curious of the memory allocation for the following code.
NSString *myString = [NSString string];
I know this will create an autoreleased empty string, #""
What happens when I then call
myString = #"Hello world";
Is my reference the same as the autoreleased object NSString provided or did I just allocate a new object that I am responsible for releasing?
When wondering whether you own an object, ask yourself:
Does the method I used to create this object...
begin with new?
begin with alloc?
contain copy?
equal retain?
If you can answer "Yes" to any of those, then you are responsible for invoking release or autorelease on the returned object. (Note that the rules for Core Foundation objects are slightly different. Also note that anything that the documentation explicitly says that contradicts this wins. The documentation always supersedes the guidelines)
In the case of your string, the answers to all your questions are "no", so you are not responsible for the object. Constant strings (of the style #"foo") are hard-coded into the application binary and cannot be deallocated. That, however, is an implementation detail. As long as you follow the memory management rules, you'll be good!
One thing I'm concerned about is I create two ints, but don't release them. Would it be better to make them NSIntegers?
-(void) flipCoin {
int heads = [headsLabel.text intValue];
int tails = [tailsLabel.text intValue];
if (random() %2 ==1 )
{
heads++;
}
else {
tails++;
}
headsLabel.text = [NSString stringWithFormat:#"%d", heads] ;
tailsLabel.text = [NSString stringWithFormat:#"%d", tails];
}
As sha notes, local variables get allocated in the current stack frame. As soon as the current function call returns, the stack gets "popped", and the memory occupied for the current call is not released so much as abandoned, until it is overwritten by the next call that gets pushed into that part of the stack.
So why do we have to release variables like this:
MyClass *myObject = [[MyClass alloc] init];
Well, you actually don't have to worry about "myObject". It's on the stack, just like your ints, and it will get cleaned up when the current call finishes.
What you have to worry about is the memory that myObject—which is a pointer—points to. It's off somewhere on the heap. Constructing an object involves asking the runtime for some semi-permanent place to put it; that process returns a memory address, which your pointer stores.
alloc and release are Objective-C idioms that largely replace C's malloc() and free() functions, but all of them ultimately are asking the computer to set aside memory on the heap, and all of that memory must ultimately be returned, either through an autorelease pool, a release message, or a free() call.
int is what is known as a primitive type. It is not a pointer to an Objective-C object so you cannot release it. You can't even send a message to it.
NSInteger is also a primitive type in the sense that it is a typedef to a primitive type (long usually). So you can't release that either.
What do you need to release? You need to release any object you obtained by sending new, alloc or a method containing copy. You also need to release objects to which you have sent retain. So all of the local variables in the following must be released:
-(void) foo
{
NSString* aString = [[NSString alloc] init];
NSString* aString2 = [aString copy];
NSString* aString3 = [someOtherString retain];
NSString* aString4 = [#"some string" copy];
}
NB due to implementation details, you would actually get away with not releasing the aString4 but you don't need to worry about it.
No. Your heads and tails variables are local and stored on the stack. This won't cause a leak. Your two NSString assignments near the bottom are created using convenience constructors and will be autoreleased for you.
All default datatypes (int, char, BOOL, etc) are automatically managed for you, and do not (and cannot) be released (for all intents and purposes).
NSIntegers behave likewise, as they are just signed ints (or signed longs on 64-bit machines).
Objects you initialize, however, like NSString or NSArray will usually have to be released (unless they are autoreleased, like the NSStrings at the bottom of your code). If you ever call -alloc and -init on something, you will have to later release it. If you ever doubt whether a method returns an autoreleased object, just read the documentation (it will tell you).
Also, if you want to read up on memory management, there are plenty of wonderful sources that will teach you (Google is a great place to start!), and if you ever think that your code leaks memory, run it through Instruments, and you'll be able to tell...