String splitting problem - objective-c

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.

Related

Memory Management Questions

I have been programming in Objective-C for a couple weeks now, and I think its time that I think more about my memory management and so I have a couple scenarios I would like clarification on.
NSString *myString = #"Hello, World";
If I were to on the next line do
NSString *anotherString = myString;
Is it getting copied? or is another string just a pointer to myString? if it's just a pointer how would I make anotherString a copy of myString that has its own memory?
What if I were to
[anotherString release];
What actually gets released, just anotherString, or does myString go away too?
Then if I were to do
anotherString = nil;
Does that actually free up memory and for use or does it still have the space allocated with empty memory? Obviously the pointer can still be used. What does it do to myString?
This will really help me become better at managing the memory properly, instead of just [object release]; randomly and causing crashes.
Thank you VERY MUCH in advance to whoever replies.
When you do:
NSString *myString = #"Hello, World";
NSString *anotherString = myString;
...you're creating a single NSString instance, and two pointers to it. So to answer your questions, no it is not being copied. Yes, anotherString is just a pointer, and so is myString, the actual NSString instance is off in memory-land, at the address that both pointers are now pointing to.
To make a copy of the string, you would do:
NSString *anotherString = [myString copy];
When you do:
[anotherString release];
The NSString instance that anotherString points to is released. Nothing happens to anotherString itself. It continues to point to your now-invalidated object instance. If myString was pointing to the same instance, then yes, this causes myString to "go away" as well.
And if you do:
anotherString = nil;
...then you've caused a memory leak, because you reassigned the pointer without releasing the thing it was pointing at. Except not in this case because #"Hello, World" is a literal value that is loaded onto the stack and is not retained by your code.
In any case, setting anotherString to nil does nothing to your string, it just changes what anotherString points to. Your actual NSString instance is still off in memory-land, completely unaware that you just threw away your reference to it (possible exception: reference counted/garbage collected environments).
And yes, calling [object release] randomly will cause crashes. As a general rule you should only call release on something if:
You called alloc and init... on it.
You called retain on it.
You obtained the object as a result of calling copy on some other object.
Note that these stack, so if you alloc something, retain it, and then copy it, you need to have 3 calls to release, two for the object that you alloc'ed, and one for the copy.
As a side note, you may find it clearer to write your object declarations like:
NSString* myString = #"Hello, World";
NSString* anotherString = myString;
...which makes it more obvious that what you are declaring are pointers to NSString's and not NSString's themselves. Personally I think your original syntax, while commonly used, is also backwards.
This string:
NSString *myString = #"Hello, World";
is created on the stack. It's loaded into memory when the app starts. You don't own the memory backing the object, and therefore shouldn't release it.
If you want to copy a string to the heap (where you can manage the memory), you simply do this:
NSString *anotherString = [myString copy];
Then you're responsible for releasing that object when you're done with it.
[anotherString release];
Setting a pointer to nil just clears the pointer, not the object it's pointing to. It's still in memory.
NSString *anotherString = myString;
--- This is just a pointer assignment
--- You can copy myString using [myString copy]
[anotherString release];
--- You are releasing the owner ship of the anotherString (please read about retain count concept)
anotherString = nil;
--- you are just assigning the pointer to nothing.
I suggest Please read more about memory management apple documents ...

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.

When not to alloc and init an NSString

Whenever I need to create a new NSString variable I always alloc and init it. It seems that there are times when you don't want to do this. How do you know when to alloc and init an NSString and when not to?
Whenever I need to create a new NSString variable I always alloc and init it.
No, that doesn't make sense.
The variable exists from the moment the program encounters the point where you declare it:
NSString *myString;
This variable is not an NSString. It is storage for a pointer to an NSString. That's what the * indicates: That this variable holds a pointer.
The NSString object exists only from the moment you create one:
[[NSString alloc] init];
and the pointer to that object is only in the variable from the moment you assign it there:
myString = [[NSString alloc] init];
//Or, initializing the variable in its declaration:
NSString *myString = [[NSString alloc] init];
Thus, if you're going to get a string object from somewhere else (e.g., substringWithRange:), you can skip creating a new, empty one, because you're just going to replace the pointer to the empty string with the pointer to the other one.
Sometimes you do want to create an empty string; for example, if you're going to obtain a bunch of strings one at a time (e.g., from an NSScanner) and want to concatenate some or all of them into one big string, you can create an empty mutable string (using alloc and init) and send it appendString: messages to do the concatenations.
You also need to release any object you create by alloc. This is one of the rules in the Memory Management Programming Guide.
If you want to initialise it to a known value, there is little point in using alloc, you can just use a string literal:
NSString* myStr = #"Some value";
If you want to initialise it with a format or whatever, but don't need it to stick around beyond the current autorelease pool lifetime, it's a bit neater to use the class convenience methods:
NSString* myTempStr = [NSString stringWithFormat:#"%d", myIntVar];
If you need its lifetime to go beyond that, either alloc/init or else add a retain to the previous call. I tend to slightly prefer the latter, but the two are pretty much equivalent. Either way you will need a balancing release later.
Note that, since NSString is not mutable, this sort of thing is not only unnecessary but actively wrong:
// don't do this!
NSString* myStr = [[NSString alloc] initWithString:#""];
myStr = someOtherStr;
since it leaks the initial placeholder value.
It seems that there are times when you don't want to do this.
I can't think of any time when I would want to alloc/init a NSString. Since NSStringgs are immutable, you pretty much always create new strings by one of:
convenience class method e.g.
NSString* foo = [NSString stringWithFormat:...];
literal
NSString* foo = #"literal";
NSString instance method
NSString* foo = [bar uppercaseString];
copy from mutable string
NSString* foo = [mutableBar copy]; // foo needs to be released or autoreleased in this case
I'm guessing that you are referring to using StringWithString or similar instead of initWithString? StringWithString alloc and inits for you under the hood and then returns an autoreleased string.
If you don't need to do any string manipulation other than to have the string, you can use NSString *str = #"string";
In general with iOS, the tighter you manage your memory the better. This means that if you don't need to return a string from a method, you should alloc init and then release it.
If you need to return a string, of course you'll need to return an autoreleased string. I don't think its any more complicated than that.

+[NSString stringWithString:] -- what's the point?

As NSString strings are immutable, what is the value of the stringWithString: class method?
I get the utility when used with NSMutableString, I just didn't see the utility with the NSString class.
You might have a NSMutableString (or some home-grown NSString subclass) that you want to duplicate.
NSMutableString *buffer = [NSMutableString string];
// do something with buffer
NSString *immutableStringToKeepAround = [NSString stringWithString:buffer];
Of course, you can also just make a copy:
NSMutableString *buffer = [NSMutableString string];
// do something with buffer
NSString *immutableStringToKeepAround = [[buffer copy] autorelease];
but you own the copy and must release or autorelease it.
As "Andy" points out in #318666, it's related to memory management, quoting:
The difference between initWithString and stringWithString is that stringWithString returns an auto-released pointer. This means that you don't need to release it specifically, since that will be taken care of next time that the auto-release pool cleans up any auto-released pointers.
initWithString, on the other hand, returns a pointer with a retain count of 1 - you do need to call release on that pointer, or else it would result in a memory leak.
(Taken from here)
Returns a string created by copying the characters from another given string
[NSString stringWithString:#"some string"]
It is equivalent to
[[[NSString alloc] initWithString:#"some string"] autorelease]
Also, if you have a pointer to an NSString, it may actually be a subclass of NSString like NSMutableString. So, if you want to store the string and be guaranteed that it doesn't change, you should make a copy of it, hence stringWithString exists.
As another use case, if (for whatever reason) you create your own subclass of NSString or NSMutableString, stringWithString: provides a handy way to instantiate it with an instance of either NSString, NSMutableString, or MyCustomString.
I often use +stringWithString: when I need to create an NSMutableString but start it with an initial value. For example:
NSMutableString * output = [NSMutableString stringWithString:#"<ul>"];
for (NSString * item in anArray) {
[output appendFormat:#"<li>%#</li>", item];
}
[output appendString:#"</ul>"];
FYI, now that we are compiling with ARC enabled, you don't have to manually release at all, ARC will insert the release calls during compile time. So how is it still different? stringWithString is still added to the autorelease pool which gets drained sometime in the future (unless you created your own autorelease pool). initWithString will have a release call right before the function ends, so if you didn't retain it somewhere in the method, you can be sure that the string is destroyed by the end of the function call. This gives you a tighter control on the memory management as opposed to using autoreleased objects.

Does [NSMutableDictionary setValue: value forKey: key] retain NSString key?

When adding items to NSMutableDictionary using the setValue:forKey: method (I suppose this generalizes to any NSObject) does the dictionary retain the second parameter, the NSString?
For example:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
NSString *theString = #"hello";
int i;
for (i=0; i<[theString length]; i++){
NSNumber *myInt = [NSNumber numberWithInt:i];
NSString *character = [NSString stringWithFormat:#"%C",[theString characterAtIndex:i]];
[dict setValue: myInt forKey:character];
}
[dict release];
[pool release];
Clearly, there is no reason to release myInt in the loop, it is retained by dict so it can't be released until the end of the code. But is the same true of character? My thinking is that if NSMutableDictionary stores the string in some other way, then one could create a temporary pool around the loop and release those strings instead of waiting until the release of the dictionary.
I am also curious as to why retainCount of character is 7fffffff as if it is an NSConstantString, I would expect stringWithFormat to return an NSString object which would need retaining, but that doesn't seem to be the case.
It's very common in Cocoa for NSString parameters to be copied instead of retained. That's because you could have just as easily given the dictionary an instance of NSMutableString. Because the string's value could change, NSDictionary makes a copy.
But, regardless of how NSMutableDictionary really operates, you don't have to worry whether character needs to be retained. Once you've passed it to NSMutableDictionary as a parameter, it's really that class's problem to decide how to store the data, unless the documentation specifically tells you that retaining the objects are your responsibility.
I also wouldn't worry too much about the retainCount of any object. Following the retain count of an object too closely can lead you down rabbit holes that just make you spin your wheels.
Finally, I really don't think you need to create your own autorelease pool here. Unless you know with absolute certainty that theString is going to be very long, or you've already observed high memory utilization in Instruments, adding the autorelease pool is an unnecessary optimization.
You don't need to retain character there, the dictionary retains it when you set it as a key and your own code has no need to retain it.
You also don't need to worry about why the retain count isn't what you expect. Maybe the Foundation framework has Flyweight-like instances of a load of single-character NSString instances. In any case if you've got the memory management correct following the guidelines, you'll be OK regardless of what the framework's doing behind the scenes. http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html