NSString and NSData Memory Management - objective-c

I have the following code for creating an NSString to contain the body of the text file and then convert it to NSData and output it to a file.
NSString *particleString = [[NSString alloc] initWithFormat:#"%#", #"This is the body of my file"];
NSData *metaVals = [particleString dataUsingEncoding:NSISOLatin1StringEncoding];
Since I have created particleString using alloc, I thought I needed to release it after I have finished converting it to NSData, hence I added
[particleString release];
But my app crashes when I add this line. However, when I remove the line where I use it to create metaVals, I can safely release it.
Can anyone explain why passing it to NSData stops me from releasing it? I believe I own particleString, what's going on?

According to your comment you do particleString = [particleString stringByAppendingFormat:#"%#", #"Some other string"]; which looses the reference to the original particleString, and replaces it with an autoreleased version. You then go on to release the autoreleased version, causing both a leak of the original particleString, and an overrelease of the new one.
Try this
NSString *particleString = [NSString stringWithFormat:#"%#", #"This is the body of my file"];
particleString = [particleString stringByAppendingFormat:#"%#", #"Some other string"];
NSData *metaVals = [particleString dataUsingEncoding:NSISOLatin1StringEncoding];
It no longer has a release because both strings are now autoreleased.
I would suggest re-reading the memory management rules

[particleString stringByAppendingFormat:#"%#", #"Some other string"];
this returns a newly created object. which means the first object created and assigned to particleString is leaking, and you are trying to release the newly, autoreleased, object that has been created by using the -stringByAppendingFormat: method
You could probably use a NSMutableString instead which has a method named
appendFormat:(NSString *)...

Related

Basic difference between following NSString assignment calls

// Directly assigning the value.
NSString *str = [objDictionary objectForKey:#"attributeName"];
// Assigning with convenience method
NSString *str = [NSString stringWithFormat:#"%#", [objDictionary objectForKey:#"attributeName"]];
// Assigning after being owner to that object.
NSString *str = [[NSString alloc] initWithString:#"%#", [objDictionary objectForKey:#"attributeName"]];
In what cases, We need to identify which one needed to be used in code. ???
Any Reference links for difference between the same???
Or can someone answer the question in depth???
Thanks for the help.
NSString *str = [objDictionary objectForKey:#"attributeName"];
This is the declaration where you want to user local variable with autorelease memory assigned
i.e. you don't need to worry about memory allocation/deallocation.
NSString *str = [NSString stringWithFormat:#"%#", [objDictionary objectForKey:#"attributeName"]];
This method is useful when you need to combine different types in single string
i.e. integer/float with string
for e.g.
NSString *str = [NSString stringWithFormat:#"%# and %d", [objDictionary objectForKey:#"attributeName"], 5];
This will result in 'your value and 5'
NSString *str = [[NSString alloc] initWithString:#"%#", [objDictionary objectForKey:#"attributeName"]];
This is the assignment where you are allocating memory and you need to have that variable to use some other place so it will be there until and unless you release the memory of that variable.
Make sure when you allocate memory you release memory yourself as you are the responsible one.
For further detailed study I recommend you to visit documentation for NSString which will give you idea about available class/instance methods and how to use.
Assuming your dictionary contains a string, under ARC, these are all identical. With manual reference counting, the first two are autoreleased and the last one is retained.
For a reference guide, you can't do much better than the NSString class reference.

Is this a correct situation to call release on an object in Objective-C?

I'm new to Objective-C and I am having some difficulty with understanding memory management.
So let's say I have a class and an instance variable of type NSString* that isn't tied to a property. Would this situation leak memory?
myString = [[NSString alloc] init];
//more program stuff
myString = [[NSString alloc] init];
Should I have called [myString release] before I set myString equal to a new object? Will this sort of code leak memory? Do I have to release an object like this every time I have the pointer point to a different object?
First, Apple's Memory Management Programming Guide is a great place to look for examples and instructions about memory management.
Now to your question. When you call myString = [[NSString alloc] init]; you are reassigning the pointer myString and as such lose access to the original NSString, thus creating a memory leak.
The general rule of thumb here is that for every alloc you should have a release and these must alternate appropriately. If you do
myString = [[NSString alloc] init];
// ...
myString = [[NSString alloc] init];
// ...
[myString release];
[myString release];
you are releasing the same instance twice which results in overreleasing and an error BAD-ACCESS. The correct thing to do is
myString = [[NSString alloc] init];
// ...
[myString release];
myString = [[NSString alloc] init];
// ...
[myString release];
so that each instance is correctly released.
For future, stick to the simple rule that for every alloc/copy/retain you should pair it with a release.
Yes this will leak.
By allocating and assigning another NSString instance to the same variable myString, you lose reference to the original content of myString and therefore the ability to send it a release message.
Both, the Clang static analyzer and the Leaks instrument should uncover this leak.
Yes, you need to release the first object before you reassign your variable to point to the second object. Otherwise, you lose track of your first object and you leak it because you can't release it. You are responsible for releasing the object because you created it (via alloc) as explained in the Memory Management Rules.
Also, bear in mind that [[NSString alloc] init] is creating an empty and immutable string (NSStrings are immutable meaning that they can not be changed after creation). There is little point in doing this.

Leak or Crash - difference between autorelease and release

I have a comprehension question. This method is given:
- (NSArray*)test {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://stackoverflow.com/"]];
NSString *result = [[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSMacOSRomanStringEncoding];
result = [result stringByAppendingString:#"something"];
NSArray *arr = [NSArray arrayWithObject:result];
//[result release];
return arr;
}
If I uncomment the release the App would crash and say it cannot access a released object.
By not releaseing the result string Instruments would report a leak (NSPlaceholderString).
I can autorelease it on the same line I alloc it, that would solve the problem (which I'm currently doing in my App).
If I understand it correctly stringByAppendingString: should create an autoreleased object so the 'old' result could be deallocated. Then the method arrayWithObject: should copy the object into an array. So my thought was to release the string after it was copied to the array.
Am I missing something or something wrong with my knowledge?
Let's go through your code line by line.
- (NSArray*)test {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://stackoverflow.com/"]];
This creates a data object. You don't own it, but it will stick around for the rest of the method's time. So far, so good.
NSString *result = [[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSMacOSRomanStringEncoding];
This creates a string object that you own. Again, no problem here — we just need to release it later.
result = [result stringByAppendingString:#"something"];
You throw away your reference to the string object that was in result and store a new string object that you do not own. This is a leak because you can no longer release the original string. Also, you're correct in noting that the new string can be treated as an autoreleased object — which means you should not release it.
NSArray *arr = [NSArray arrayWithObject:result];
Contrary to your belief, this does not copy anything. It merely keeps a reference to the new string and retains it.
//[result release];
You should not release result at this point, because the object it contains is not one you own — you got it from stringByAppendingString:, not from a method with new, alloc, retain or copy in its name. Releasing this object that you do not own will almost certainly result in a crash at some point. The old object that you own and should release was lost two lines earlier, and releasing something else in its place won't help.
result = [result stringByAppendingString:#"something"];
This line replaces the first allocated string by a new autoreleased string.
So the first string is leaked and the second one should not be released. This explains why uncommenting the release line crashes.

String splitting problem

I am work on a simple program in which I split a string and a user global, I use the following code for splitting the string.
NSString *GlobleStr;//globale variable
//===============
NSString *xmlParsingResult=#"Apple,iphone";
NSArray *array = [xmlParsingResult componentsSeparatedByString:#","];
NSString *StrResult = [NSString stringWithFormat:#"%#", [array objectAtIndex:0]];
GlobleStr =[NSString stringWithFormat:#"%#",[array objectAtIndex:1]];
NSLog(#"cmd %#",StrResult);
NSLog(#"value%#",GlobleStr);
my code can split the string and o/p is cmd:Apple value:iphone
but my problem is that as soon as I call another xib then my global variable will be empty or nil and the application will crash ( it throws error like Variable is not cfstring).
Any suggestions?
It's because NSString's +stringwithFormat: method returns an autoreleased string. In a local variable this is often what you want to prevent memory leaks (otherwise you have to manually release the string when you're done with it). The problem here is that the string in GlobleStr is getting released by the autorelease pool sometime after you assign it, then when you try to access it in another place you get a crash.
The fix is this: GlobleStr = [[NSString stringWithFormat:#"%#",[array objectAtIndex:1]] retain];
As an aside, you can just do this instead:
GlobleStr = [[array objectAtIndex:1] retain];
I strongly recommend reading Apple's documentation regarding memory management in Cocoa: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html .
Finally, without seeing your code I can't say for sure, but I'd be curious to know why you're using a global variable for GlobleStr. It's a blanket statement, and there are certainly exceptions, but when programming in Cocoa there's probably a better way to structure your code.
You need to retain your global, otherwise it will be deallocated when the autorelease pool drains:
GlobleStr = [[NSString stringWithFormat:#"%#", [array objectAtIndex:0]] retain];
Remember to release it later on when you're done -- in particular, before assigning any other value to it.

Releasing of strings

I got a doubt that when should the strings are released.I am not made any allocation to the string is there any necessary to release the string?
No if you do not "allocate" the string they are auto released.
for example
NSString *aTestString = [NSString stringWithFormat:#"Hello %#",#"World"];
This string is auto released, so you do not have to call [aTestString release];
If you would do:
NSString *aTestString = [[NSString alloc] initWithFormat:#"Hello %#",#"World"];
Then you would need to release it by [aTestString release]; because you manually allocated.
Therefore it is wise to autorelease it, so you do not have to think of it later on
NSString *aTestString = [[[NSString alloc] initWithFormat:#"Hello %#",#"World"] autorelease];
But that would just be the same as the first piece of code I gave ya.
Back to the point, no you do not have to manually release it as long as you do not allocate it yourself.
Did you create the string via a call to alloc, new, or a method containing copy? Did you explicitly retain the string yourself? If you got the NSString from a CFStringRef, did you create the CFStringRef with a function that included create? If not, you don't have to do anything. If you did, you have to either release or autorelease the string.
Object allocation/deallocation rules
You need to call [Object release] if and only if:
You called [Object alloc]
You called [Object retain]
You called [Object new]
If you did not explicitly allocate or retain the object, then you need to release it. If you got the object via a class method, the method did something like this: return [[[Object alloc] init] autorelease];. This allocates a new object, but is autoreleased when the NSAutoReleasePool next gets a chance.