memory management in Objective C,NSString - iphone

What I did is
int main(int argc, char *argv[]){
NSString *str = [[NSString alloc] init];
str = #"a a a a a a a a a ";
[str release];
NSLog(#"string is %#",str);
return 0;
}
I think string will be nil because we release it before printing it. However, it is not. Therefore, my consumption is wrong.
Can anybody advice me and correct me. Any comments are welcomed. Thanks

You are leaking memory there, first you allocate a new, empty, NSString object and then you assign a static string literal to the pointer, effectively leaking the memory you previously allocated. Then you release an object that you don't own as pointed out by The Saad and then you should note that release doesn't set the pointer to nil but just releases the object which might or might not end in an de-allocation (which, assuming that it would dealloc the object, would also not set the pointer back to nil).

NSString *str = [[NSString alloc] init];
This declares a variable that is a pointer to an instance of NSString, allocates memory for an instance of NSString, initialises that memory, then assigns a pointer to that memory to the variable you declared.
str = #"a a a a a a a a a ";
This creates an NSString constant and assigns a pointer to it to the variable that you declared. As you no longer have a reference to the original NSString object you created, you have leaked the memory you allocated for it.
[str release];
This declares that this code no longer wishes to be an owner of the memory allocated to str. As you created it with a string literal, this object will always exist in your program, and releasing it does nothing.
I think string will be nil because we release it before printing it.
Releasing an object does not ever set it to nil.

The str variable is a pointer to the string object and essentially contains a memory address. Sending a message like retain to the object does not change the value of the variable.
Just because the string is released will not cause the variable to lose its value. You must expicitly set the variable to nil for that to happen.
Note that with ARC under iOS 5 you can get weak references/pointers which will become nil when their underlying object is released. You do this by prepending a variable declaration with the __weak keyword (or use weak in a property declaration).

String constants are not to be released; they're neither explicitly to be released neither autoreleased; they're simply constants (by the way, they're deallocated at end of scope).
So, only -release them if you previously retained them

Here is the source corrected:
I'm afraid that there is much to learn before fully understanding what is going on. You should also look at understanding malloc (don't use it though), and how pointers work in C.
int main(int argc, char *argv[]){
NSString *str = [[NSString alloc] initWithString:#"a a a a a a a a a "];
[str release];
str = nil;
NSLog(#"string is %#",str);
return 0;
}
int main(int argc, char *argv[]){
NSString *str = #"a a a a a a a a a ";
// DONT Call this - the str [str release]; - no need to release this kind of string
NSLog(#"string is %#",str);
return 0;
}

Related

Getting NSString from char * (Converting C's char-pointer)

I want to show the char * in the UITextField
What I tried:
char *data;
char *name=data+6;
txtName.text=[[NSString alloc] initWithCString:name encoding:NSUTF8StringEncoding];
but I am not getting the correct value.
To create an NSString from a const char *, simply use these methods:
Returns an autoreleased object:
/**
* Should be wrapped in `#autoreleasepool {...}`,
* somewhere not far in call-stack
* (as closer it's, the lower our memory usage).
*/
NSString *stringFromChar(const char *input) {
return [NSString stringWithUTF8String: input];
}
Whenever we return an object (maybe to Swift), we need to register into nearest #autoreleasepool block (by calling autorelease method to prevent memory-leak, according to ownership-rules), but ARC does that automatically for us.
But even with ARC disabled, we are NOT forced to call autorelease manually, like:
return [[NSString stringWithUTF8String: name] autorelease];
Generally, convenience factory methods (like stringWithUTF8String:), already call the autorelease method (or should if ARC disabled), because the class simply does not intend to own the instance.
Creates a retained object:
NSString *result = [[NSString alloc] initWithUTF8String: name];
// ... Do something with resulted object.
// NOTE: calling below is not required
// (If ARC enabled, and should cause compile error).
[result release];
Update 2021 about difference; With ARC enabled, these two methods are equivalent (i.e. ARC will auto-call autorelease method; always registering to nearest #autoreleasepool).
Reference.
If you are not getting the correct value, then something is wrong with the data. Add a few NSLog calls to see what the strings contain.
What do you expect? You have an uninitalized char*. Then you add 6 to the pointer, which is already undefined behaviour. Then you try to turn a pointer pointing to any old rubbish (and you have no idea where it is pointing) to an NSString*. Nothing good can come from this.
Define a char* pointing to an actual, real C string using ASCII or UTF-8 encoding. Then create an NSString like this:
char* cstring = "Try harder";
NSString* objcstring = #(cstring);
You can use [NSString stringWithUTF8String: data].

Objective C: Allocating Memory

I am new to Objective C and here is my confusion:
When is it applicable to allocate memory for an instance?. Like this:
When is it applicable to use this...
NSString *str = [[NSString alloc]init];
and to use this...
- (NSString *) formatStr:(NSString *) str{
NSString *str = (NSString *) str;
...
.....
.......
}
and even creating UIActionSheet, it uses alloc but in other UI elements, it does not..
What exactly the reason and when shall it be done?
Thanks fellas.. :D
In addition to the "normal" allocation route (i.e. through [[MyClass alloc] init]) some classes provide so called "factory methods". These are class methods that allocate objects internally. The advantage of using factory methods is that they can create a suitable subclass to return to the caller. In both cases, though, the allocation is ultimately done by alloc/init.
Objective C's alloc method handles allocating memory, you don't have to worry about allocating, just managing the retain and release cycles.
checkout this About Memory Management article from Apple
when you create an instance using alloc+init OR you get an instance through a method that has init in the name (a convention, e.g. initWithString) you are said to own the object, this is, you must not retain it (its ref counter is already set to 1) and need to eventually release it when you are done with it. When you receive an instance by calling a method which hasn't get init in the name (rule on thumb but you should always check documentation) this means that you are not the owner of the object, i.e. the object might be released at any time, even while you are using it. Usually methods such as stringWithFormat will return autoreleased objects which will be around until the end of the event cycle (unless you claim ownership by calling retain on the string).
I strongly recommend reading the cocoa memory management guide.
NSString *str = [[NSString alloc]init]; //you own the object pointed to by str. Its retain count is 1. If you don't call release this will be a memory leak.
- (NSString *) formatStr:(NSString *) str{
NSString *str = (NSString *) str; //you don't own str. btw, you don't need casting here
//using str here might throw exception if its owner has released it
[str retain]; //you own str now. you can do whatever you want with it. It's yours
.......
}

retainCount shows MaxInt

After trying to print retainCount of object I get 2147483647. Why do I get such a result? It should be 1, shouldn't?
NSString *myStr = [NSString new];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
2011-09-08 17:59:18.759 Test[51972:207] refCount = 2147483647
I use XCode Version 4.1. Tried compilers GCC 4.2 and LLVM GCC 4.2 - the same result.
Garbage Collection option was set to unsupported.
NSString is somewhat special when it comes to memory management. String literals (something like #"foo") are effectively singletons, every string with the same content is the same object because it can't be modified anyway. As [NSString new] always creates an empty string that cannot be modified, you'll always get the same instance which cannot be released (thus the high retainCount).
Try this snippet:
NSString *string1 = [NSString new];
NSString *string2 = [NSString new];
NSLog(#"Memory address of string1: %p", string1);
NSLog(#"Memory address of string2: %p", string2);
You'll see that both strings have the same memory address and are therefore the same object.
This doesn't directly answer your question, but retainCount is not really all that useful and should not be used for testing. See this SO post for details.
When to use -retainCount?
While NSString's are an odd case (there are others in the framework) you might also run across this in other clases - it's one of the ways of creating a singleton object.
A singleton only exists once in the app and it's pretty important that it never gets released! Therefore, it will overwrite some methods of NSObject including (but not limited to):
- (id)release {
// Ignore the release!
return self;
}
- (NSUInteger)retainCount {
// We are never going to be released
return UINT_MAX;
}
This object can never be released and tells the framework that it's a singleton by having a ludicrously high retain count.
Checkout this link for more information about singleton objects.
I've seen this a couple of times regarding NSStrings, the retainCount returns the maximum count instead of the actual one when you try to look at retainCounts of strings in this manner.
Try this;
NSString *myStr = [[NSString alloc] init];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
Edit: Restored NSUInteger

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.

How does autoreleasing work in Objective-C?

I am just reading through the Practical Memory Management guide.
I am somewhat confused by this block of code:
- (void)printHello {
NSString *string;
string = [NSString stringWithFormat:#"Hello"];
NSLog(#"%#", string);
}
It seems to me that string is going to have a reference count of 0. Is this true?
What stops string from being deallocated before we call NSLog(string)?
Is this somehow equivalent to this:
- (void)printHello {
NSString *string;
string = [[[NSString stringWithFormat:#"Hello"] retain] autorelease];
NSLog(#"%#", string);
}
Edit: Similarly this code is given in the Practical Memory Management
guide:
- (NSString *)fullName {
NSString *string = [NSString stringWithFormat:#"%# %#", firstName, lastName];
return string;
}
When and how does the return value get freed? Who is the owner? Does the caller of fullName need to release the string returned by full name?
Strictly speaking,
- (void)printHello {
NSString *string;
string = [NSString stringWithFormat:#"Hello"];
NSLog(#"%#", string);
}
Is not equivalent to
- (void)printHello {
NSString *string;
string = [[[NSString stringWithFormat:#"Hello"] retain] autorelease];
NSLog(#"%#", string);
}
The convention is that a method should autorelease any object it returns. The only exception (AFAIK) is for constructors, which return an object with a +1 retain count. Since [NSString stringWithFormat:] returns an object. In first snippet, stringWithFormat: returns an already autoreleased object. the second snippet, you're retaining it once more and it'll be released twice (which has the same effect, but the second retain/autorelease pair is redundant).
Ok, now to answer your question. Essentially, every time UIKit calls your code, it creates an NSAutoreleasePool object. Every time you autorelease an object, its added to this pool. Finally, when your code returns back to UIKit, it calls the drain method on the pool (i.e [pool drain]) and that releases every object which has been added to the pool and deallocates the pool. Also, autorelease pools can be nested, so you can create your own pools and drain them if you're going to be creating a lot of autoreleased objects. It isn't as complicated as it sounds.
I'd highly recommend that you read the Autorelease Pools chapter in the Memory Management Guide (Which incidentally, comes right after the Practical Memory Management chapter).
First of all:
NSLog(string);
Don’t do this. (I just realized it comes right from the Apple docs. Weird.) The first argument to NSLog is the formatting string. If your string contains some percent escapes, bad things will happen. The correct, if slightly longer way is:
NSLog(#"%#", string);
Now to the point: Autoreleased objects do not have zero retain count. They have retain count 1+ and have a pending –1 operation on them that will happen “soon in the future”.
The precise meaning of “soon in the future” depends on the situation. If you’re on the main thread and there is no additional autorelease pool in place, autoreleased objects will be released on the next runloop iteration. This does not have to be the case if you have an additional release pool:
// Let’s pretend this is a long loop and you don’t want to wait
// for the autoreleased objects to be collected by the main pool.
for (…) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *foo = [NSString stringWith…];
[pool drain];
// Now foo is no longer valid.
}
As for returning autoreleased objects, that’s one of the main use cases for autoreleasing. You are returning an object that will perish “soon”, but if the caller is interested, he can retain and take over the ownership. (It’s like, if you pardon the image, passing a bomb with a burning safety fuse. If the caller is interested, he’ll put out the fuse by retaining.) And if the caller is not interested, like maybe he’s ignoring an output from a function or just uses the value to construct some other object, he does not do anything and the object will get out of memory:
- (id) createObject {
return [NSString stringWith…];
}
- (void) interestedCaller {
NSString *value = [[self createObject] retain];
}
- (void) notInterestedCaller {
[self createObject]; // maybe just interested in side effects
NSString *differentString = [NSString stringWithString:[self createObject]];
}
This is really convenient and makes the manual memory management quite pleasant. You might be interested in run loops and the Objective-C tutorial by Scott Stevenson.