On objective-c with iPhone:
I want to make a append with strings, but can I use autorelease? Is this right?
NSString *str1 = [[NSString alloc] initWithString:#"STR1"];
NSString *str2 = [[NSString alloc] initWithString:#"STR2"];
NSString *s = [[str1 autorelease] stringByAppendingString:[str2 autorelease]];
will this remove the *str1 and *str2 memory?
And for example, if I have a method:
+(void) doSomething
{
NSString *str1 = [[NSString alloc] initWithString:#"STR1"];
NSString *str2 = [[NSString alloc] initWithString:#"STR2"];
NSString *s = [[str1 autorelease] stringByAppendingString:[str2 autorelease]];
[[NSClassFromString(s) alloc] init];
}
should I dealloc the *s pointer???
The general rule is that if you call alloc you have to call release on that resource.
So for your first example, str1 and str2 will be removed from memory, however you're not following convention for your autoreleases. Instead add the autorelease to the allocation line:
NSString *str1 = [[[NSString alloc] initWithString:#"STR1"] autorelease];
NSString *str2 = [[[NSString alloc] initWithString:#"STR2"] autorelease];
For the second example, because you're not calling alloc for the stringByAppendingString method, you don't need to release s.
Read through the iPhone Memory Management guide. It is worth the up front investment, so that you don't have to deal with these issues down the road. After that, read through Akosma Software's blog post.
Related
In my app, I have a view where user have to fill a form. But, sometime the app crash here, in this function, that simple cacth the value field and built a url to give
-(NSString*)urlToUpload{
NSString *string1 =[[NSString alloc]init];
string1= [NSString stringWithFormat:#"?nombre="];
NSString *string2 = [string1 stringByAppendingString:nameAdded];
//crash here
NSString *string3 = [string2 stringByAppendingString:#"&horario="];
NSString *string4 = [string3 stringByAppendingString:horarioAdded];
NSString *string5 = [string4 stringByAppendingString:#"&info="];
NSString *string6 = [string5 stringByAppendingString:infoAdded];
NSString *string7 = [string6 stringByAppendingString:#"&offerta="];
NSString *string8 = [string7 stringByAppendingString:offertaAdded];
NSString *lat_string = [[[NSString alloc] initWithFormat:#"%f",locationToUpload2.latitude] autorelease];
NSString *lon_string = [[[NSString alloc] initWithFormat:#"%f",locationToUpload2.longitude] autorelease];
NSString *string9 = [string8 stringByAppendingString:#"&latitude="];
NSString *string10 = [string9 stringByAppendingString:lat_string];
NSString *string11 = [string10 stringByAppendingString:#"&longitude="];
NSString *string12 = [string11 stringByAppendingString:lon_string];
NSString *url1 = [NSString stringWithFormat:#"http://myserverside/mysql_up.php"];
NSString *url = [url1 stringByAppendingString:string12];
return url;
}
EDIT:
It seems problem appers on nameAdded when there is a white space into textField(i.e. MisterB not crash, Mister B yes ).
But I am using:
nameAdded =[[nameField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
and NSLOg give of nameAdded is Mister%20B.
The crash still appearing...
Just use a single stringWithFormat::
- (NSString *)urlToUpload {
NSString *url = [NSString stringWithFormat:#"http://myserverside/mysql_up.php?nombre=%#&horario=%#&info=%#&offerta=%#&latitude=%f&longitude=%f",
[nameAdded stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[horarioAdded stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[infoAdded stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[offertaAdded stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
locationToUpload2.latitude, locationToUpload2.longitude];
return url;
}
Make sure the referenced variables are valid.
In your original code there is no need to alloc/init an NSString then assign another string to the same variable. That's a memory leak (string1).
If you really want to structure your code the way you have it, at least use an NSMutableString and append to that one mutable string. Creating over a dozen NSString variables is the wrong way to do it.
Updated: Ensure each of the strings added to the URL are properly escaped.
It looks like nameAdded may be the cause of your problems. Is it nil at that point?
Also
You are allocating a string, setting it to string1 and then immediately setting string1 to the class function stringWithFormat which allocates another string. Also you are using stringWithFormat but you aren't using any format so you could simply use NSString *string1 = #"?nombre=";
Rather than declaring all of those variables you should just use NSMutableString and build it all in one variabl
This question already has answers here:
Releasing objects returned by method
(2 answers)
Closed 9 years ago.
I have this function, and I don't use ARC:
-(NSString *)getDataFileDestinationPath
{
NSMutableString *destPath = [[NSMutableString alloc] init];
[destPath appendString:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]];
[destPath appendFormat:#"/%#.%#", dataFileName, dataFileExtension];
return destPath;
[destPath release];
}
So without the release message I have a great memory leak in leaks analysis. So I added the [destPath release]; message but when I try to use this method - as I can see during the debug process - this line of the code wasn't called at all. So after return message the control goes to the next method. Where should I implement the release function to free the memory?
This is what autorelease has been invented for.
return [destPath autorelease];
Or initially don't alloc-init the string object, just create an originally autoreleased instance:
NSMutableString *destPath = [NSMutableString string];
You need to use autorelease in this case.
-(NSString *)getDataFileDestinationPath
{
NSMutableString *destPath = [[NSMutableString alloc] init];
[destPath appendString:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]];
[destPath appendFormat:#"/%#.%#", dataFileName, dataFileExtension];
[destPath autorelease];
return destPath;
}
char arr[] = "abcdefg";
// I know I can do this
NSString *s = [[NSString alloc] initWithCString:arr encoding:NSUTF8StringEncoding];
If I want to convert part of the arr array into an NSString*? say cde rather then the whole string abcdefg? How do I achieve that?
NSString *s = [[NSString alloc] initWithBytes:arr + 2
length:3 encoding:NSUTF8StringEncoding];
I've created autorelease pool. localString has added to this pool. I released the pool. localString and string must be deallocated. But in reality they are still alive. You can see my log:
Why is the string object still alive? I don't know.
and code:
-(NSString*) happyString
{
NSString *localString = [[[NSString alloc] initWithString:#"I don't know."] autorelease];
return localString;
}
-(IBAction) onButton:(id)sender
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *string = [self happyString];
[pool release];
NSLog(#"Why is the string object still alive? %#", string);
}
Strings (NSString instances and statically allocated strings with #"") are immutable in Cocoa, so when you try to create a new NSString from a statically allocated one, the NSString class can make an optimisation: a new NSString instance is not created (the object created when you called -alloc is immediately released), and the reference to your statically allocated string is returned. That is, the line:
NSString *localString = [[[NSString alloc] initWithString:#"I don't know."] autorelease];
Is actually equivalent to:
NSString *localString = #"I don't know.";
(If you check the memory addresses of those two objects, you can see that they are the same.)
As this type of string cannot be released, it does not disappear when you expect it to.
If you were to create your string in a way that cannot be optimised, for example:
NSString *localString = [[[NSString alloc] initWithFormat:#"%#", #"I don't know."] autorelease];
Then your code will behave as you expect, and your application will (hopefully) crash at your NSLog line.
If you have tried any classes (any custom classes) other than NSString , then it would not be alive..
Hi I am trying to write to a file from the accelerometer data. Here is my code:
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
//xax.text = [NSString stringWithFormat:#"X:[%2.6f]",acceleration.x];
//yax.text = [NSString stringWithFormat:#"Y:[%2.6f]",acceleration.y];
//zax.text = [NSString stringWithFormat:#"Z:[%2.6f]",acceleration.z];
NSString *acc_x = [[NSString alloc] initWithFormat:#"X:[%2.6f]",acceleration.x];
NSString *acc_y = [[NSString alloc] initWithFormat:#"Y:[%2.6f]",acceleration.y];
NSString *acc_z = [[NSString alloc] initWithFormat:#"Z:[%2.6f]",acceleration.z];
xax.text = acc_x;
yax.text = acc_y;
zax.text = acc_z;
[acc_x release];
[acc_y release];
[acc_z release];
//wfm == 2 //Initialization of Appending to the file
if (wfm == 2)
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *txtFileName = [[NSString alloc] initWithFormat:#"tmp/%#.txt",txtName.text];
NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:txtFileName];
//NSString *fileName = [NSHomeDirectory() stringByAppendingPathComponent:#"tmp/acc_w_trial2.txt"];
//Current Contents of the file
NSString *fileCurrent = [[NSString alloc] initWithContentsOfFile:fileName];
//Date and Time of each Accelerometer Data
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd 'at' HH:mm:ss:SSS"];
NSDate *date = [NSDate date];
NSString *formattedDateString = [dateFormatter stringFromDate:date];
NSString *msg = [[NSString alloc] initWithFormat:#"%#%# %#%#%# \n",fileCurrent,formattedDateString,xax.text,yax.text,zax.text];
//Convert NSstring to NSData
NSData* data=[msg dataUsingEncoding: [NSString defaultCStringEncoding]];
//bool fileCreationSuccess = [fileManager createFileAtPath:fileName contents:data attributes:nil];
[fileManager createFileAtPath:fileName contents:data attributes:nil];
[msg release];
[dateFormatter release];
[fileCurrent release];
[txtFileName release];
}
}
I get the warning level 1 and level 2. Is there a way I can release the NSFileManager memory to prevent this from locking up?
Your handler method to collect accelerometer data seems not very performant. You are allocating the resources (memory, file) everytime which can take a long time.
You should allocate the needed resources only once (i.e. use dispatch_once) and keep the file open. Use a NSFileHandle (method fileHandleForWritingAtPath) in order to append the data at the end of the file.
Furthermore NSHomeDirectory() is not where you're supposed to save user data, as iOS apps are sandboxed.
Either use NSTemporaryDirectory() or write in the Documents or Library Folder. The following is from Apple's sample code, usually in application delegate class:
- (NSString *)applicationDocumentsDirectory {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
You can try using an Autorelease Pool.