I used Instrument to check if I had any leaks in my script and it came with a couple particularly in my NSDateFormatter. It says I had it:
Leaked Object # Address Size Responsible Library Responsible Frame
NSDateFormatter 70 < multiple > 1.09 KB DAF +[XMLParser dateFromString:]
This is my method it points at and I cannot find any leak:
+ (NSDate *)dateFromString:(NSString *)dateString
{
NSDateFormatter *nsDateFormatter = [[NSDateFormatter alloc] init];
[nsDateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm"];
NSDate *date = [nsDateFormatter dateFromString:dateString];
return date;
[nsDateFormatter release];
}
Can anybody help me with this one? I have no idea where to look this is my first time with Instruments.
You are returning date before releasing the formatter.
+ (NSDate *)dateFromString:(NSString *)dateString
{
NSDateFormatter *nsDateFormatter = [[NSDateFormatter alloc] init];
[nsDateFormatter setDateFormat:#"yyyy-MM-dd'T'HH:mm"];
NSDate *date = [nsDateFormatter dateFromString:dateString];
[nsDateFormatter release]; //Release here
return date;
//Code after a return does not get executed!!!
}
Make your return statement the last statement. As you have written it, [nsDateFormatter release] is never called, because the function is returning before it can execute that line.
Related
i know the preferred way of get a new NSDate is [NSDate date]. but i'm just confused why the following code would ever throw the exception "message sent to deallocated instance"
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MM/dd/yyyy"];
NSDate *dateFromStr = [[NSDate alloc] init];
// produce date object
dateFromStr = [dateFormatter dateFromString:self.releaseDate];
[dateFormatter setDateFormat:#"MM.dd.yyyy"];
NSString *strDate = [dateFormatter stringFromDate:dateFromStr];
[dateFormatter release];
[dateFromStr release];
this code is in a viewcontroller that is used as a "virtual" view by another viewcontroller..something similar to this: http://cocoawithlove.com/2009/01/multiple-virtual-pages-in-uiscrollview.html
Your first problem is that you declare dateFromStr by allocating an NSDate object, then you leak that object when you assign the result of the first call to dateFromStr:. You could simplify (and eliminate the leak) thusly:
NSDate *dateFromStr = [dateFormatter dateFromString:self.releaseDate];
What you need to know about this is that you are not allocating this object, so you don't need to release it. Unless you call a method like alloc (and there are a couple others; search SO for other posts about memory management), then you are not responsible for releasing the object.
So in the code you posted, the last line is releasing an object you didn't allocate and causing your error.
Instead of
NSDate *dateFromStr = [[NSDate alloc] init];
// produce date object
dateFromStr = [dateFormatter dateFromString:self.releaseDate];
You should use just
NSDate *dateFromStr = [dateFormatter dateFromString:self.releaseDate];
Otherwise you overwrite the object and loose the address of the old one.
After that you're trying to release the new one by your hands, and then there's an attempt of garbage collector to release it. Whereas your first allocated object is leaking.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MM/dd/yyyy"];
NSDate *dateFromStr = [[NSDate alloc] init];
// produce date object
Here you are creating a dateFromStr, let's call him "John".
dateFromStr = [dateFormatter dateFromString:self.releaseDate];
[NSDateFormatter dateFromString] will return a new object, "Tom", which has been already autoreleased. You have lost any reference to "John", which has leaked.
[dateFormatter setDateFormat:#"MM.dd.yyyy"];
NSString *strDate = [dateFormatter stringFromDate:dateFromStr];
[dateFormatter release];
[dateFromStr release];
Here you are sending a [release] message to an object which was already [autoreleased]. The end result is that you will have invoked [release] twice on "Tom", and zero times on "John".
You can rewrite your code like this:
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"MM/dd/yyyy"];
// produce date object
NSDate *dateFromStr = [dateFormatter dateFromString:self.releaseDate];
[dateFormatter setDateFormat:#"MM.dd.yyyy"];
NSString *strDate = [dateFormatter stringFromDate:dateFromStr];
I created a method to return the NSDate from a NSString. Code is below. I send to the function "2/25/2011". The function returns "2010-12-26 08:00:00 +0000"
What did I do wrong? Also the NSString I need to release at the end. How do I do that?
thank you!
-(NSDate *) GetDatefromString:(NSString *) Str
{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM-dd-YYYY"];
NSDate *dateFromString;
// = [[NSDate alloc] init]; tried taking this part out but still not working
if (Str != NULL)
{
dateFromString = [formatter dateFromString:Str];
}
else
{
dateFromString = [formatter dateFromString:#"1/1/1970"];
}
[formatter release];
return dateFromString;
// how do I release dateFromString?
/*
Printing description of dateFromString:
2010-12-26 08:00:00 +0000
Printing description of Str:
02-25-2011
*/
}
You are passing in a date using the / seperator but you specified - as a separator for your date formatter. As to your question on releasing the string, you should only release objects that you own, i.e. that you have created with new, alloc, copy, or mutableCopy. See examples below.
NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; // needs releasing
[formatter setDateFormat:#"MM-dd-yyyy"];
NSString* str1 = #"06/25/2011"; // does not need releasing
NSString* str2 = [[NSString alloc] initWithString:#"06-25-2011"]; // needs releasing
NSDate* date1 = [formatter dateFromString:str1]; // does not need releasing
NSDate* date2 = [[NSDate alloc] init]; // needs releasing
date2 = [formatter dateFromString:str2];
NSLog(#"date from %# : %#", str1, date1);
NSLog(#"date from %# : %#", str2, date2);
// release the objects you own
[formatter release];
[str2 release];
[date2 release];
// prints out
date from 06/25/2011 : (null)
date from 06-25-2011 : 2011-06-25 00:00:00 -0700
you set the format to#"MM-dd-YYYY"but the string you pass in has the form #"1/1/1970". That doesn't match. see Data Formatting Guide: Date formatters.
// how do I release dateFromString?
With autorelease.
return [dateFromString autorelease];
See Memory management.
The problem I had was the format had CAP LETTERS for the YEAR.
This is correct:
[formatter setDateFormat:#"MM/dd/yyyy"];
And this is wrong: NOTE THE CAPS YYYY
[formatter
setDateFormat:#"MM-dd-YYYY"];
I've always had some issues getting the infamously picky NSDateFormatter from causing memory instability in my code. I must not grasp how to use it properly. I've looked at tons of sample code and modeled my method after this, but it seems memory issues still plague me. The issues I'm having is that this method is creating a zombie - not too sure how / why. Some insight would be wonderful!!
-(NSString *)getTimeZoneFormatedDate:(int)subtractMinutes TimeZoneOffset:(NSString *)timeZoneOffset
{
float timeZoneOffsetInt = [timeZoneOffset floatValue];
//Calculate the requested UTC time
NSDate *UTCDateTimeNow = [NSDate date];
NSDate *UTCDateTimePast = [UTCDateTimeNow dateByAddingTimeInterval:((subtractMinutes*60)+(timeZoneOffsetInt*60*60))];
//Round the minutes down
NSDateComponents *time = [[NSCalendar currentCalendar]
components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:UTCDateTimePast];
int minutes = [time minute];
float minuteUnit = floorf((float) minutes / 10);
minutes = minuteUnit * 10;
//Format the minutes string
NSString *minuteString;
minuteString = [NSString stringWithFormat:#"%d",minutes];
if ([minuteString length] < 2)
minuteString = [#"0" stringByAppendingString:minuteString];
//Format the rest of the date & time
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:#"UTC"];
NSDateFormatter *dateFormatter;
dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setTimeZone:timeZone];
[dateFormatter setDateFormat:#"yyyy-MM-dd, HH:"];
NSString *yearMonthDayHourString = [dateFormatter stringFromDate:UTCDateTimePast];
//Put the two together and return it!
return [yearMonthDayHourString stringByAppendingString:minuteString];
}
I'm implementing it like so:
NSString *timeZoneText = [self getTimeZoneFormatedDate:minuteModifier*-10 TimeZoneOffset:radarTimeZoneOffset];
If I run my project with the dateformatter commented out and my method just returning:
return #"blah blah";
No issues - everything runs bug free. So, I believe it's safe to assume the issue lies within! Thanks for the help!
I think the problem is that your "NSString *yearMonthDayHourString" is autoreleased string.
You can retain it in your implementation code something like that
self.timeZoneText = blabla if timeZoneText is property with retain
or just [timeZoneText retain]; and release later;
You can try out NSDateFormatter's getObjectValue:forString:range:error: method. Maybe returned NSError provides you a reasonable explanation why it failed.
On the other hand there might be an easier way to get the result:
NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"dd-MMM-yyyy HH:mm:ss"];
NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
[dateFormatter setLocale:usLocale];
[usLocale release];
return [dateFormatter stringFromDate:date];
I am trying to clean up memory leaks and other issues in an existing iPhone app. I am a little new to Objective C, but have some good programming fundamentals and a general understanding of the memory management that is required when dev'ing iphone apps. My question is about the following method below.
-(NSDate *)formatDate:(id)value{
NSLog(#"eja: DetailViewController/ formatDate()");
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss.S"];
[dateFormatter release];
return [dateFormatter dateFromString:value];
}
It is returning an error reading "Referenced-counted object is use after it is released". I see that dateFormatter is being freed before it is returned/used. The issue is of course that if you put the release after the return statement you get a 'Potential leak of an object' error associated with dateFormatter var declaration.
I also tried "autorelease"
return [[dateFormatter dateFromString:value] autorelease];
But I then get the error 'Object sent - autorelease too many times'.
Any words of advice on how to write this properly so the variables are properly managed?
Replace
[dateFormatter release];
with
[dateFormatter autorelease];
and it should work!
You can create an NSDate before you release the NSDateFormatter:
-(NSDate *)formatDate:(id)value
{
NSLog(#"eja: DetailViewController/ formatDate()");
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss.S"];
NSDate *date = [dateFormatter dateFromString:value];
[dateFormatter release];
return date;
}
This way, your allocated NSDateFormatter gets released as it should while the object you are returning doesn't require manual memory management.
Instead of writing [dateFormatter release], you can autorelease it, and even save a line of code in the process.
- (NSDate *)formatDate:(NSString *)value {
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss.S"];
return [dateFormatter dateFromString:value];
}
I have this code that simple returns Today's date as a string formatted:
+(NSString*) getTodayString_YYYY_MM_DD {
NSDate * today = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd"];
return [[formatter stringFromDate:today] autorelease];
}
With instruments I'm not getting a memory leak, but when I Analyze, XCode says:
Object sent -autorelease too many times
If I understand correctly, I have to release manually the formatter as I'm creating it using 'alloc', but I can't release here because I have to return the value, so I add the autorelease.
How I can do it better to improve it ?
thanks,
r.
You are -autoReleasing the NSString, not the formatter.
You don't need an autoRelease since -stringFromDate: is giving you an already autoReleased string.
Here is one way your code can look like:
+(NSString*) getTodayString_YYYY_MM_DD {
NSDate * today = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy-MM-dd"];
NSString *retString = [formatter stringFromDate:today];
[formatter release];
return retString;
}
Given that an NSDate's description is always in the format YYYY-MM-DD HH:MM:SS ±HHMM:
+ (NSString *) getTodayString_YYYY_MM_DD
{
return [[[NSDate date] description] substringToIndex:10];
}
Just throwing it out there. It's probably less efficient than the NSDateFormatter method.