Using objective-c on the iPhone, what is wrong with this code?
Is it leaking memory? Why?
How would I do this correctly?
NSMutableString *result = [NSMutableString stringWithFormat:#"the value is %d", i];
... then later in my code... I might need to change this to:
result = [NSMutableString stringWithFormat:#"the value is now %d", i];
I need to use stringWithFormat a 2nd time... but isn't that creating a NEW string and not correctly freeing the old one?
No, it doesn't leak memory because stringWithFormat: returns an autoreleased object.
You could use the instance method "setString" for your already existing NSMutableString, like this:
[ result setString:[NSString stringWithFormat:#"the value is now %d", i] ];
If you really want to reuse the string, you can use something like
[result setString:#""];
[result appendFormat:#"the value is now %d", i];
However, unless you notice a performance/memory problem, just use
NSString *result = [NSString stringWithFormat:#"the value is %d", i];
/* ... */
result = [NSString stringWithFormat:#"the value is now %d", i];
It's generally easier to work with immutable objects because they can't change under your feet.
What you have seems to me to be the natural way to replace a mutable string with new content, unless you have other references to the same mutable string elsewhere.
If you don't have other references to it and you are reusing the string only to improve performance/memory footprint, that sounds like premature optimisation.
By the way, you do not own a string you obtain via stringWithFormat: so you do not need to (Indeed must not) release it.
Related
If I take a following question. What is the best way to initialize NSMutableString Class?
(All instance will be return at unexpected times... so I'll assume that the initialization as follows:)
If I know in advance the amount of work. ( expected )
NSMutableString *str1 = [NSMutableString stringWithString:#""];
NSMutableString *str2 = [NSMutableString stringWithCapacity:0];
NSMutableString *str3 = [NSMutableString stringWithCapacity:1000];
NSMutableString *str4 = [NSMutableString string];
for(int i = 0; i< 1000; i++)
{
//The following tasks.(Adding to the string to continue working.)
[/*str1~str4*/ appendFormat:#"%d", i];
}
If I don't know in advance the amount of work. ( unexpected )
NSMutableString *str1 = [NSMutableString stringWithString:#""];
NSMutableString *str2 = [NSMutableString stringWithCapacity:0];
NSMutableString *str3 = [NSMutableString stringWithCapacity:1000];
NSMutableString *str4 = [NSMutableString string];
for(int i = 0; i< /*a large of size(unpredictable)*/ ; i++)
{
//The following tasks.(Adding to the string to continue working.)
[/*str1~str4*/ appendFormat:#"%d", i];
}
Largely split into two when performing these tasks, What is the best way to initialize?
I sometimes when working with these task is also confusing.
Case 1
Of the options listed, I'd use:
NSMutableString *str3 = [NSMutableString stringWithCapacity:1000];
…if you know the destination size, or estimate it with a little room at the top and are able to quickly determine the exact size, or the size worst case scenario, this could save multiple reallocate and copy operations. If you don't know the size in the worst case scenario, or if it takes a lot of time to calculate, then you may as well use [NSMutableString string] or [NSMutableString new]. Also, *WithCapacity is a hint, which the frameworks are free to ignore.
Of course, the body of your loop and the size you reserve also implies that all the values are [0…9] (specifically, that all values consume one character), and you could in that case likely do far better by using format strings with more arguments. However, i is obviously larger than 9 for most iterations, and will consume on average 3 characters each, so 3000 would be a more appropriate reserve capacity for the exact code you posted.
Case 2
Of the options listed, I'd use:
NSMutableString *str4 = [NSMutableString string];
Even better, if you don't need to add it to an autorelease pool: [NSMutableString new] or [[NSMutableString alloc] init].
Other Notes
Yes, keeping objects out of autorelease pools (e.g. use alloc+init) can improve performance and reduce peak memory usage significantly. Sometimes, this is beyond your control, and in some environments (e.g. ARC), this may happen even though you use an autoreleased convenience constructor - e.g. [NSMutableString string].
The Faster Solution
Finally, if this case you have outlined really is a performance concern, the fastest way would be to create a char buffer on the stack and then create one NSString from the result of copying the numbers over to the char buffer. Assuming your ints are all 0-9, it would be very fast and easy, then simply create an NSString from the (terminated) cstring. You can even do this if the input size varies, or is very large (results in a very long string).
It doesn't really matter.
If you've optimized your program so far that this decision will have a measurable effect on its overall performance, pat yourself on the back or, as Sheldon from BBT would say, "have a chocolate!"
PS:
If you precisely know the size up front or have a really good estimate on it, then use that size in stringWithCapacity: or initWithCapacity: if you don't, then don't even bother — let the framework decide, it's pretty damn clever!
Here is the shortest way:
NSMutableString *string = [#"" mutableCopy];
NSMutableString *str1 = [NSMutableString stringWithString:#""];
Bad, a NSString (#"") is pointlessly created, then copied into a new NSMutable String
NSMutableString *str2 = [NSMutableString stringWithCapacity:0];
Bad, a NSMutableString with 0 capacity will need to be inflated upon the first addition to it.
NSMutableString *str3 = [NSMutableString stringWithCapacity:1000];
Good, if 1000 has some significance (i.e. it's an expected size for the content you're working with).
NSMutableString *str4 = [NSMutableString string];
Good, using a convenience method, which is is like doing [NSMutableString alloc] init];
If you know the size upfront, use
[NSMutableString stringWithCapacity: _Known_Size_];
If you don't know the size up front, use
[NSMutableString stringWithCapacity: _small_number_];
Then the mutable string will grow as it needs to.
In Swift 5:
var mutableString = NSMutableString("")
It is always better to allocate and initialize an object, not use a class method to create it (which puts it in the closest autorelease pool).
So,
NSMutableString* stringOne = [[NSMutableString alloc] initWithCapacity:capacity];
instead of
NSMutableString* stringTwo = [NSMutableString stringWithCapacity:capacity];
Just remember that you have to release stringOne when you are done with it, but not stringTwo, because the stringWithCapacity: class method returns an autoreleased object.
Read more about the topic here: http://www.mulle-kybernetik.com/artikel/Optimization/opti-5.html
I am kind of new to iOS development.
I want to retrieve strings from the text(.rtf) file I have. The file is within my application main bundle. It's content are:
#start word1 First word end word2 Second word end //lots of things to be added later
Code:
path = [[NSBundle mainBundle]pathForResource:#"words" ofType:#"rtf"];
if(path)
{
NSLog(#"path exists");
}
NSError *error = nil;
NSString *file = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if(error)
{
NSLog(#"error");
}
NSString *finalword= [[NSString alloc]init ];
NSString *startfrom = [[NSString alloc] initWithFormat:#"word%i",i+1];
i++;
NSLog(#"%#",startfrom);
NSString *wordoftheday = [[NSString alloc]init ];
NSScanner *scanner = [NSScanner scannerWithString:file];
[scanner scanUpToString:startfrom intoString:nil];
[scanner scanUpToString:#"end" intoString:&wordoftheday];
finalword = [wordoftheday substringFromIndex:[startfrom length]];
NSLog(#"%#",finalword);
Word.text = final word; //change label text
//[final word release];
//[wordoftheday release];
//[file release];
Code is working fine but it leaves me with memory management issues. App crashes if I release the variables in the last commented code.
Also this method is in my viewdidload. I want the label to change text when user click a button. I will have to write the same code again in that method which leaves me with more memory issue.
So looking at these one by one, focusing on the memory issues and not the overall strategy here:
NSString *finalword= [[NSString alloc]init ];
Here you alloc/init a new immutable and empty NSString, and then you end up overwriting the pointer to this later anyway. You should just delete this line. And then you'll need to move the declaration down a few lines to this:
NSString *finalword = [wordoftheday substringFromIndex:[startfrom length]];
Then you have:
NSString *startfrom = [[NSString alloc] initWithFormat:#"word%i",i+1];
This one you need to release later. Or just change it to:
NSString *startfrom = [NSString stringWithFormat:#"word%i",i+1];
Then you have:
NSString *wordoftheday = [[NSString alloc]init ];
Same story as finalword. Except that you do need to define this variable so you can pass it to the scanner later. So change it to:
NSString *wordoftheday = nil;
And lastly, you can release 'file'. That is fine. But you don't want to release 'wordoftheday' or 'finalword' because you don't own those strings. You did not create them yourself.
And one other note:
if(error)
That is not the correct way to check for an error in loading 'file'. You should check the return from the method and then look for an error if and only if the return value was nil. So change that line to:
if(!file)
(OK, that wasn't really a memory issue, but a bug I did notice.)
I think that's all of it at least as far as memory issues. I hope that helps.
make those variables as member variables and release in the dealloc
I have this:
partenaire_lat = 48.8160525;
partenaire_lng = 2.3257800;
And obtain a NSString like this:
NSString *endPoint =[NSString stringWithFormat:#"%#,%#", partenaire_lat, partenaire_lng];
and after using this NSString in some context I get this stupid error:
Variable is not a CFString.
But if I create the NSString like this:
endPoint = #"48.8160525,2.3257800" it then works perfect!
For this error Variable is not a CFString I tried the following:
NSString *endPoint1 =[NSString stringWithFormat:#"%#,%#", partenaire_lat, partenaire_lng];
CFStringRef endPoint =(CFStringRef)endPoint1;
and tried to use endPoint but not working neither this way.Anyone any miraculous idea?Thx
EDIT:partenaire_lat and partenaire_lng are both NSString!!
You have
partenaire_lat = 48.8160525;
partenaire_lng = 2.3257800;
You keep saying that the two variables are NSStrings but you aren't assigning NSStrings to them. You need to assign NSString objects to NSString variables - they aren't created for you automatically.
So the answers which are telling you to use formatted strings are correct. You really should be doing it like this:
partenaire_lat = [[NSString stringWithFormat:#"%f", 48.8160525] retain];
partenaire_lng = [[NSString stringWithFormat:#"%f", 2.3257800] retain];
what are lat and lng? i'm assuming float or double..so you should use [NSString stringWithFormat:#"%f,%f", lat, lng]; (or however you want the floats to be formatted)
You code has several potential problems:
%# format specifier expects object parameter, while it looks like you pass plain float (I may be wrong here as there's not enough context to be sure). Change format to %f to fix your problem if that's really the case:
NSString *endPoint1 =[NSString stringWithFormat:#"%f,%f", partenaire_lat, partenaire_lng];
Your endPoint1 string is autoreleased and may become invalid outside of current scope if you don't retain it. So if you try to use your variable in another method you probably should retain it.
All you need to do
NSString *latStr=[[NSNumber numberWithFloat:partenaire_lat] stringValue];
NSString *lngStr=[[NSNumber numberWithFloat:partenaire_lng] stringValue];
and do whatever you want to do with these two string :)
I would like to know how to selectively trim an NSMutableString. For example, if my string is "MobileSafari_2011-09-10-155814_Jareds-iPhone.plist", how would I programatically trim off everything except the word "MobileSafari"?
Note : Given the term programatically above, I expect the solution to work even if the word "MobileSafari" is changed to "Youtube" for example, or the word "Jared's-iPhone" is changed to "Angela's-iPhone".
Any help is very much appreciated!
Given that you always need to extract the character upto the first underscore; use the following method;
NSArray *stringParts = [yourString componentsSeparatedByString:#"_"];
The first object in the array would be the extracted part you need I would think.
TESTED CODE: 100% WORKS
NSString *inputString=#"MobileSafari_2011-09-10-155814_Jareds-iPhone.plist";
NSArray *array= [inputString componentsSeparatedByString:#"_"];
if ([array count]>0) {
NSString *resultedString=[array objectAtIndex:0];
NSLog(#" resultedString IS - %#",resultedString);
}
OUTPUT:
resultedString IS - MobileSafari
If you know the format of the string is always like that, it can be easy.
Just use NSString's componentsSeparatedByString: documented here.
In your case you could do this:
NSString *source = #"MobileSafari_2011-09-10-155814_Jareds-iPhone.plist";
NSArray *seperatedSubStrings = [source componentsSeparatedByString:#"_"];
NSString *result = [seperatedSubStrings objectAtIndex:0];
#"MobileSafari" would be at index 0, #"2011-09-10-155814" at index 1, and #"Jareds-iPhone.plist" and at index 2.
Try this :
NSString *strComplete = #"MobileSafari_2011-09-10-155814_Jareds-iPhone.plist";
NSArray *arr = [strComplete componentsSeparatedByString:#"_"];
NSString *str1 = [arr objectAtIndex:0];
NSString *str2 = [arr objectAtIndex:1];
NSString *str3 = [arr objectAtIndex:2];
str1 is the required string.
Even if you change MobileSafari to youtube it will work.
So you'll need an NSString variable that'll hold the beginning of the string you want to truncate. After that one way could be to change the string and the variable string values at the simultanously. Say, teh Variable string was "Youtube" not it is changed to "MobileSafari" then the mutable string string should change from "MobileSafari_....." to "YouTube_......". And then you can get the variable strings length and used the following code to truncate the the mutable string.
NSString *beginningOfTheStr;
.....
theMutableStr=[theMutableStr substringToIndex:[beginningOfTheStrlength-1]];
See if tis works for you.
How to connect string "Hello" and string "World" to "HelloWorld"? Looks like "+" doesn't work.
NSString *string = [NSString stringWithFormat:#"%#%#", #"Hello", #"World"];
NSLog(#"%#", string);
That should do the trick, although I am sure there is a better way to do this, just out of memory. I also must say this is untested so forgive me. Best thing is to find the stringWithFormat documentation for NSString.
How about:
NSString *hello = #"Hello";
NSString *world = #"World";
NSString *helloWorld = [hello stringByAppendingString:world];
If you have two literal strings, you can simply code:
NSString * myString = #"Hello" #"World";
This is a useful technique to break up long literal strings within your code.
However, this will not work with string variables, where you'd want to use stringWithFormat: or stringByAppendingString:, as mentioned in the other responses.
there's always NSMutableString..
NSMutableString *myString = [NSMutableString stringWithString:#"Hello"];
[myString appendString: #"World"];
Note:
NSMutableString *myString = #"Hello"; // won't work, literal strings aren't mutable
t3.text=[t1.text stringByAppendingString:t2.text];
Bill, I like yout simple solution and I'd like to note that you can also eliminate the space between the two NSStrings:
NSString * myString = #"Hello"#"World";