Using NSDate in While loop - objective-c

I want to get the current date using [NSDate date] in a While Loop. I accomplish this by doing like this:
while (interval > 0.0) {
NSDate *currentDate = [[NSDate alloc] init];
currentDate = [NSDate date];
interval = (float) [newDate timeIntervalSinceDate: currentDate] / 60;
[currentDate release];
}
I dont know why is the Memory leaks shows that there is a great amount of memory is leaked. Kindly guide me that what is the right way to accomplish my task.

In line NSDate *currentDate = [[NSDate alloc] init]; you create a new object, which you should release. In line currentDate = [NSDate date]; you do not release an old object, you only make a pointer to point to another object. In line [currentDate release]; you release an object created on the second line of a loop, which may cause an error (that object is marked as autorelease one and iOS will clean it for you). You should rewrite your code like:
while (interval > 0.0) {
NSDate *currentDate = [NSDate date];
interval = (float) [newDate timeIntervalSinceDate: currentDate] / 60;
}

You don't need the first line NSDate *currentDate = [[NSDate alloc] init];. You can directly assign the [NSDate date] to currentDate.
NSDate *currentDate = nil;
while (interval > 0.0) {
currentDate = [NSDate date];
interval = (float) [newDate timeIntervalSinceDate: currentDate] / 60;
}

The problem is not that you are leaking per se but that you are running in a while loop.
The auto released dates are growing in the autorelease pool because the pool only empties in the idle time on the run loop.
One solution is to create a local autorelease pool within the scope of the while
while (foo) {
NSAutoreleasePool *aPool = [[NSAutoreleasePool alloc ] init];
NSDate *currentDate = [NSDate date];
// other computational foo
[aPool release]
}
When you release the pool in the local scope it will immediately drop the autoreleased date you requested.

Related

Error when convert float to datatime

I have this command that is being called each second in background mode, Every time he is called I add +1 to my variable of type float, and convert to date format:
xis = (xis + 1) / 000001;
//The Format which you want as output
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
dateFormat.dateFormat = #"ss:mm:hh";
[dateFormat setTimeZone:[NSTimeZone systemTimeZone]];
//The Format in which your dateTime currently is
NSDateFormatter *dateFormat1 = [[NSDateFormatter alloc] init];
dateFormat1.dateFormat = #"hh.mm";
[dateFormat1 setTimeZone:[NSTimeZone systemTimeZone]];
NSString *timeStr = [NSString stringWithFormat:#"%.2f",xis];
NSDate *dates = [dateFormat1 dateFromString:timeStr];
NSLog(#"Time: %#", [dateFormat stringFromDate:dates]);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
recordTime.text = [NSString stringWithFormat:#"%#",[dateFormat stringFromDate:dates]];
}];
But this code has a problem when the time comes 00:00:12, something goes wrong and the time is the value (null), which may be causing this and how can I solve?
There are two issues:
I would advise against using the NSTimer routine to keep track of elapsed time yourself. Timers may not be called with the frequency you expect. Also, if the user suspended the app and came back to it, you don't really want to try to keep this timer going while the app is no longer in the foreground. In short, you want to decouple the updating of the UI from the calculation of the elapsed time string representation.
So, instead, one should capture the "start time" and then have the routine get the current time, compare that to the "start time" and calculates the string representation of this elapsed time. But notably, there is no incrementing of variables for seconds elapsed, but rather one should rely on the system time of the device.
Your formatting problem stems from the awkward conversion of your numeric counter to a date string. The problem was complicated by the fact that the formatting string that was backwards, ss:mm:hh.
First (and to my above point), I'd probably calculate the time elapsed in seconds, by capturing the start time up front and store it in a CFAbsoluteTime property:
self.start = CFAbsoluteTimeGetCurrent();
And, if you really wanted to use NSDateFormatter, instead of using it to interpret a numeric value, I would only use it for converting to and from NSDate objects. You could, for example, get the NSDate for 00:00:00, use dateByAddingTimeInterval to add the elapsed time to the date, and then use the formatter to get the output string:
// calculate the time elapsed in seconds
CFTimeInterval elapsed = CFAbsoluteTimeGetCurrent() - self.start;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"HH:mm:ss";
NSDate *start = [formatter dateFromString:#"00:00:00"];
NSDate *end = [start dateByAddingTimeInterval:elapsed];
NSString *elapsedString = [formatter stringFromDate:end];
Having said that, I'd probably favor a couple of different approaches. One is to just calculate hours, minutes, and seconds manually:
// calculate the time elapsed in seconds
CFTimeInterval elapsed = CFAbsoluteTimeGetCurrent() - self.start;
// convert this to hours, minutes, and seconds
double seconds;
double minutes;
double hours;
seconds = modf(elapsed / 60.0, &minutes) * 60.0;
minutes = modf(minutes / 60.0, &hours) * 60.0;
// create format string
NSString *elapsedString = [NSString stringWithFormat:#"%02.0f:%02.0f:%04.1f", hours, minutes, seconds];
Or a completely different approach would be to use NSCalendar. In this scenario, one might have a NSDate property that you initialize with the start time:
self.startDate = [NSDate date];
And then you could do something like:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDateComponents *components = [calendar components:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:self.startDate toDate:now options:0];
NSString *elapsedString = [NSString stringWithFormat:#"%02ld:%02ld:%02ld", (long)components.hour, (long)components.minute, (long)components.second];
Just a few approaches. But I'd advise against manually incrementing your counter manually, and I might suggest one of these latter techniques.

Problems formatting dates

Here is the set up, I have a JSON feed I am using and I want to find the difference between two specific dates called posted_date and planned_expiration_date. They are in an odd format I so I thought I could truncate them down to just the date.I could then use NSTimeInterval to find the difference in seconds.
// Time Interval Left
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
NSString *startDate = [firstPerson objectForKey:#"posted_date"];
NSString *endDate = [firstPerson objectForKey:#"planned_expiration_date"];
//Ammend the strings to YYYY-MM-DD
[formatter setDateFormat:#"yyyy-mm-dd"];
int newlength = 9;
NSDate *startDateAmmended =[formatter dateFromString:[startDate substringFromIndex:newlength]];
NSDate *endDateAmmended = [formatter dateFromString:[endDate substringFromIndex:newlength]];
Here is the bit I'm not too sure about. The date appears something like this "2013-06-07T13:40:01Z" straight from the feed. I don't know how to deal with the T and Z chars in the date formatter method so I truncate the string with substringFromIndex to make it 10 chars and then attempted the following code.
//Difference in Date
NSTimeInterval *startDifference = [startDateAmmended timeIntervalSinceNow];
NSTimeInterval *endDifference = [endDateAmmended timeIntervalSinceNow];
NSTimeInterval timeDifferenceInSeconds = startDifference - endDifference;
I get the following error, .../JSONParser/ViewController.m:52:21: Initializing 'NSTimeInterval *' (aka 'double *') with an expression of incompatible type 'NSTimeInterval' (aka 'double') at the first two calls to NSTimeInterval.
I am sure I'm going wrong in a few places and I'm sure this isn't the easiest method of doing it. Could anyone recommend how I would fix this issue or an easier way to go about getting the differences between dates?
Your error comes from your lines that say:
NSTimeInterval *startDifference = [startDateAmmended timeIntervalSinceNow];
NSTimeInterval *endDifference = [endDateAmmended timeIntervalSinceNow];
They should be:
NSTimeInterval startDifference = [startDateAmmended timeIntervalSinceNow];
NSTimeInterval endDifference = [endDateAmmended timeIntervalSinceNow];
Or, more simply, don't define those two difference variables at all, and just use:
NSTimeInterval timeDifferenceInSeconds = [endDateAmmended timeIntervalSinceDate:startDateAmmended];
To calculate the difference between two ISO 8601 / RFC 3339 date strings, you can do:
NSDate *startDate = [self dateFromISO8601String:#"2013-06-01T16:27:35Z"];
NSDate *endDate = [self dateFromISO8601String:#"2013-06-07T13:40:01Z"];
NSTimeInterval elapsed = [endDate timeIntervalSinceDate:startDate];
NSLog(#"Time elapsed (in seconds) is %.0f", elapsed);
where dateFromISO8601String is defined as:
- (NSDate *)dateFromISO8601String:(NSString *)string
{
static NSDateFormatter *formatter = nil;
if (formatter == nil)
{
formatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
formatter.locale = enUSPOSIXLocale;
formatter.dateFormat = #"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'";
formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
}
return [formatter dateFromString:string];
}
You can get the difference in seconds between two NSDate objects like this:
double difference = [startDateAmmended timeIntervalSinceDate:endDateAmmended];
Note that with the substring operation you don't have the time, only the date, so the difference will be in seconds but with steps of whole days.

How to countdown from a NSDate and display it in hours and minutes

I'm trying to countdown from a NSDate and display it in hours and minutes. Like this: 1h:18min
At the moment my date is updating to a UILabel and counting down but displaying like this:
Here's the code I'm using. A startTimer method and a updateLabel method
- (void)startTimer {
// Set the date you want to count from
// convert date string to date then set to a label
NSDateFormatter *dateStringParser = [[NSDateFormatter alloc] init];
[dateStringParser setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.000Z"];
NSDate *date = [dateStringParser dateFromString:deadlineDate];
NSDateFormatter *labelFormatter = [[NSDateFormatter alloc] init];
[labelFormatter setDateFormat:#"HH-dd-MM-yyyy"];
NSDate *countdownDate = [[NSDate alloc] init];
countdownDate = date;
// Create a timer that fires every second repeatedly and save it in an ivar
NSTimer *timer = [[NSTimer alloc] init];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateLabel) userInfo:nil repeats:YES];
}
- (void)updateLabel {
// convert date string to date then set to a label
NSDateFormatter *dateStringParser = [[NSDateFormatter alloc] init];
[dateStringParser setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.000Z"];
NSDate *date = [dateStringParser dateFromString:deadlineDate];
NSDateFormatter *labelFormatter = [[NSDateFormatter alloc] init];
[labelFormatter setDateFormat:#"HH-dd-MM"];
NSTimeInterval timeInterval = [date timeIntervalSinceNow]; ///< Assuming this is in the future for now.
self.deadlineLbl.text = [NSString stringWithFormat:#"%f", timeInterval];
}
thanks for any help
- (NSString *)stringFromTimeInterval:(NSTimeInterval)interval
{
NSInteger ti = (NSInteger)interval;
NSInteger seconds = ti % 60;
NSInteger minutes = (ti / 60) % 60;
NSInteger hours = (ti / 3600);
return [NSString stringWithFormat:#"%02i:%02i:%02i", hours, minutes, seconds];
}
Since you use NSTimeInterval ,you are getting the time interval ,ie the difference, in seconds, to display it in hours and minutes you need to apply mathematics logic and convert it!
You many need a few loops to do it.
try this
Regards

NSDate Returning nil

basically I am trying to store todays date but every time I try to do that NSDate returns nil to me
self.calendarView.selectedDate = [NSDate date];
I am new to objective-c so maybe I am doing something wrong here but it seems fairly straight forward.
[NSDate date] will return a correct date. Check if your self.calendarView is not nil at this point by doing:
NSLog(#"calendar: %#", self.calendarView);
NSDate *now = [NSDate date];
NSLog(#"now: %#", now);
self.calendarView.selectedDate = now;

How can I make a Date to jump every n seconds?

I want to make the date to change one day every "n" seconds, like a time machine. I have this code but nothing happens, any help will be appreciated.
this is the code: no issues, no error ... no tomorrow date!
-(IBAction)jumpDate
{
NSDateFormatter *dateFormater = [[NSDateFormatter alloc]init];
[dateFormater setDateFormat:#"dd MMMM yyyy h:mm:ss"]; //dateFormater.dateStyle =NSDateFormatterLongStyle; //USA date style MMMM-dd-yyyy
[dateFormater setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"CDT"]];
NSDate *todayDate = [[NSDate alloc]init];
[gregDate setText : [dateFormater stringFromDate:todayDate]];
[NSString stringWithFormat:#"dd MMMM yyyy", dayCount];
dayCount++;
if (dayCount >= 365)
{
dayCount = 365;
[timerDate invalidate];
}
}
//and the timer
- (void)viewDidLoad
{
NSDateFormatter *dateFormater = [[[NSDateFormatter alloc]init]autorelease];
[dateFormater setDateFormat:#"dd MMMM yyyy"];
NSTimeInterval secondsPerDay = 86400 ; // = 24 * 60 * 60
NSDate *today = [[[NSDate alloc]init]autorelease];
NSDate *tomorrow;
tomorrow = [today dateByAddingTimeInterval:(NSTimeInterval)secondsPerDay];
[gregDate setText : [NSString stringWithFormat:#" %# ",tomorrow]];
dayCount = 1;
timerDate=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(jumpDate)userInfo:nil repeats:YES];
[super viewDidLoad];
}
I have 3 questions, not all directly related to your question.
Why -(IBAction)jumpDate is an IBAction, if you are calling this method from your code you should changed it to (void) and if an IBAction need to call that, call it from an other method that would be the action for that button.
Is there a missing space in your code before userInfo in this call :
timerDate=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(jumpDate)userInfo:nil repeats:YES];
Did you verified that your IBOutlet are all set properly? I've stop counting the times I've forgot that.
[gregDate setText : [NSString stringWithFormat:#" %# ",tomorrow]];
What is gregDate? is it an IBOutlet pointing to a UILabel?
And you've probably verified this, but, that call retunr a valid string?
You should not call your IBAction method from your timer, for 2 reasons,
1. I really think it's bad design, it's introducing confusion on the role of this method since it's also call from a timer.
2. The method signature doesn't match the one NSTimer needs
aSelector:
The message to send to target when the timer fires. The selector must have the following signature:
- (void)timerFireMethod:(NSTimer*)theTimer
This text come from the NSTimer class reference.
Replace this line:
NSDate *todayDate = [[NSDate alloc]init];
with this line:
NSDate *todayDate = [[NSDate date] dateByAddingTimeInterval:dayCount * 86400];