ios how to change an image at specific time - objective-c

I have an image that i want to display as a sun during daytime i.e. from 6am to 6pm, and moon from 6pm to 6am.
I have successfully implemented that but the problem is the image would not change when it reaches the specified time unless re-run the apps before the image change itself.
I don't want to use NSTimer to check the time, like every second. The only possible solution i think of is using NSLocalNotification but I'm a newbiew to it. any help? =)
-(void) dayOrNight
{
NSDate* date = [NSDate date];
NSDateFormatter* dateFormat = [[NSDateFormatter alloc]init];
[dateFormat setDateFormat:#"HHmm"];
NSString* dateString = [dateFormat stringFromDate:date];
NSNumber* currentTime = [NSNumber numberWithInt:[dateString intValue]];
NSNumber* daytime = [NSNumber numberWithInt:600];
NSNumber* nightime = [NSNumber numberWithInt:1800];
NSLog(#"current time: %#",dateString);
dayNight = [[UIImageView alloc] initWithFrame:CGRectMake(265, 10, 50, 50)];
if ( [currentTime doubleValue] >= [daytime doubleValue] && [currentTime doubleValue] <= [nightime doubleValue] )
{
dayNight.image = [UIImage imageNamed:#"Sun.png"];
}
else
{
dayNight.image = [UIImage imageNamed:#"moon.png"];
}
[self.view addSubview:dayNight];
}

Local notification should be fine, I guess.
Here you can get all needed code snippets to implement execution of dayOrNight method at needed time. Also, you shouldn't add new view every time you change the picture.

I think it is impossible to do without NSTimer. U can set refreshTime by yourself (for example 1 min/ if u don`t want to do it every second)))
Or u can call this method in other methods, which are working in your class every time...
maybe u have some object, which u use during your class is working...
-(IBAction)myButtonWhichIPressDuringIworkHere {
///some actions
[self dayOrNight];
}
In other case you should to use NSTimer

you don't need to check the time at every second.
this is one of the possible solutions. it has been tested on real device only.
your UIYourViewController.m
- (void)viewWillAppear:(BOOL)animated {
NSDate *_currentDate = [NSDate date];
NSDateFormatter *_dateFormatter = [[NSDateFormatter alloc] init];
[_dateFormatter setDateFormat:#"yyyy-MM-dd' 06:00AM +0000'"]; // set the morning date here
NSString *_morningDateString = [_dateFormatter stringFromDate:_currentDate];
[_dateFormatter setDateFormat:#"yyyy-MM-dd' 06:00PM +0000'"]; // set the evening date here
NSString *_eveningDateString = [_dateFormatter stringFromDate:_currentDate];
[_dateFormatter setDateFormat:#"yyyy-MM-dd hh:mma zzz"];
NSDate *_morningDate = [_dateFormatter dateFromString:_morningDateString];
NSDate *_eveningDate = [_dateFormatter dateFromString:_eveningDateString];
NSTimeInterval _intervalToMorningDate = [_morningDate timeIntervalSinceDate:_currentDate];
NSTimeInterval _intervalToEveningDate = [_eveningDate timeIntervalSinceDate:_currentDate];
if (_intervalToMorningDate > 0) {
// now it is night
dayNight.image = [UIImage imageNamed:#"moon.png"];
[self performSelector:#selector(replaceTheBackgoundForMorning) withObject:nil afterDelay:_intervalToMorningDate];
} else {
// now it is daytime
dayNight.image = [UIImage imageNamed:#"Sun.png"];
[self performSelector:#selector(replaceTheBackgoundForEvening) withObject:nil afterDelay:_intervalToEveningDate];
}
}
- (void)viewDidDisappear:(BOOL)animated {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
and finally you should add them to your same .m file:
-(void)replaceTheBackgoundForMorning {
// reaplce the backgound here
dayNight.image = [UIImage imageNamed:#"Sun.png"];
}
- (void)replaceTheBackgoundForEvening {
// reaplce the backgoung here
dayNight.image = [UIImage imageNamed:#"moon.png"];
}

Related

Working with Date and Time separately using NSDatePickerView on Xcode

I have a part of app that set date and time of an appointment. For this, I have two NSDatePickerView. The first one I set to NSDatePickerModeDate, while the other one to NSDatePickerModeTime. But actually they should be referring to a same NSDate object inside a NSMutableDictionary entry. I know about NSDatePickerModeDateTime, but I need the date and time to be picked separatedly.
I know how to set up the NSDatePickerView to show and hide and event control and such, but at the event control UIControlEventValueChanged fire for NSDatePickerView, I'm confused on how to code the change for this, and also how to initialise the pickers (datePicker.date = today, timePicker.date = "9:00 AM")
#interface MyViewController () {
NSMutableDictionary *data;
}
#end
#implementation MyViewController
#synthesize datePicker, timePicker;
- (void) viewDidLoad {
[super viewDidLoad];
data = [[NSMutableDictionary alloc] init];
[data setObject:[NSDate date] forKey:#"date"];
datePicker.datePickerMode = UIDatePickerModeDate;
timePicker.datePickerMode = UIDatePickerModeTime;
[datePicker addTarget:self action:#selector(changeDate:) forControlEvents:UIControlEventValueChanged];
[timePicker addTarget:self action:#selector(changeTime:) forControlEvents:UIControlEventValueChanged];
datePicker.date = data[#"date"]; //????
timePicker.date = data[#"date"]; //????
}
- (IBAction) changeDate:(id)sender {
UIDatePickerView *dp = (UIDatePickerView *)sender;
[data setObject:dp.date forKey:#"date"]; //????
}
- (IBAction) changeTime:(id)sender {
UIDatePickerView *tp = (UIDatePickerView *)sender;
[data setObject:tp.date forKey:#"date"]; //????
}
The part that I don't know how to code it is denoted by //????. I've read about NSDateFormatter, NSCalendar, and some kind of date components on some answers, but that was actually making me more confused as it also throws strings and structs into the mix, what to use to do what and when. Please help.
You can set both date pickers to the same date and time. The unused part is there but it isn't displayed and can't be changed. When the user changes the value of one date picker you have to set the other date picker to the same value.
- (IBAction)changeDate:(id)sender {
NSDatePicker *dp = (NSDatePicker *)sender;
[data setObject:dp.dateValue forKey:#"date"];
self.timePicker.dateValue = dp.dateValue;
}
- (IBAction)changeTime:(id)sender {
NSDatePicker *tp = (NSDatePicker *)sender;
[data setObject:tp.dateValue forKey:#"date"];
self.datePicker.dateValue = tp.dateValue;
}
u can try this
///Convert Full date to only date
- (IBAction) changeDate:(UIDatePickerView *)sender {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"MM/dd/yyyy"];
NSString *dateStr = [dateFormatter stringFromDate:[sender date]];
[data setObject:dateStr forKey:#"date"];
}
///convert Date to only time format
- (IBAction) changeTime:(UIDatePickerView *)sender {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"hh:mm a"];
NSString *dateStr = [dateFormatter stringFromDate:[sender date]];
[data setObject:dateStr forKey:#"Time"];
}

Objective-c timer wont invalidate

Here is my situation: I am making a countdown app which works fine but does not appear to stop when I call [stopWatchTimer invalidate];, and I have no idea why. Here is my code:
- (IBAction)btnStartPressed:(id)sender {
//Start countdown with the time on the Date Picker.
timeLeft = [pkrTime countDownDuration];
[self currentCount];
lblTimer.text = time; //sets the label to the time set above
pkrTime.hidden = YES;
btnStart.hidden = YES;
btnStop.hidden = NO;
//Fire this timer every second.
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/1.0
target:self
selector:#selector(reduceTimeLeft:)
userInfo:nil
repeats:YES];
}
- (void)reduceTimeLeft:(NSTimer *)timer {
//Countown timeleft by a second each time this function is called
timeLeft--;
// Get the system calendar
NSCalendar *sysCalendar = [NSCalendar currentCalendar];
// Create the NSDates
NSDate *date1 = [[NSDate alloc] init];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:timeLeft sinceDate:date1];
// Get conversion to months, days, hours, minutes
unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *conversionInfo = [sysCalendar components:unitFlags fromDate:date1 toDate:date2 options:0];
int sec = [conversionInfo second];
int min = [conversionInfo minute];
int hour = [conversionInfo hour];
NSString *seconds = [NSString stringWithFormat:#"%d",sec];
NSString *minutes = [NSString stringWithFormat:#"%d",min];
if (sec <= 9)
seconds = [NSString stringWithFormat:#"0%d", sec];
if (min <= 9)
minutes = [NSString stringWithFormat:#"0%d", min];
if ([conversionInfo hour] == 0)
time = [NSString stringWithFormat:#"%#:%#", minutes, seconds];
else
time = [NSString stringWithFormat:#"%d:%#:%#", hour, minutes, seconds];
lblTimer.text = time; //sets the label to the time set above
NSLog(#"%d", timeLeft);
if (timeLeft == 0) {
[self timerDone];
[stopWatchTimer invalidate];
stopWatchTimer = nil;
}
}
-(void)timerDone {
pkrTime.hidden = NO;
btnStart.hidden = NO;
btnStop.hidden = YES;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Timer Done" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alert show];
[self playAlert];
}
Please let me know what the problem is... I cannot find a problem with my code anywhere!
In your btnStartPressed: method, you have nothing preventing a second NSTimer from being allocated and assigned to stopWatchTimer. If you press the button twice, you'll end up with two timers, but only one will ever be invalidated.
Add something like:
if (stopWatchTimer) return;
To the beginning of btnStartPressed:. If that doesn't fix the problem, then there isn't enough context to know for sure what is going on beyond conjecturing that timeLeft is zero?
What Nate said, but here is another explanation.
Imagine if you do this (where stopWatchTimer is a global or instance variable, doesn't matter):
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:....];
Now, do this:
stopWatchTimer = nil;
[stopWatchTimer invalidate];
The timer won't invalidate, but it'll still fire. stopWatchTimer is a reference to the object. It isn't the object itself. Thus, when you assign a second timer to stopWatchTimer, you are overwriting the reference to the first timer, but that timer is still going to fire!

Reliably checking whether NSDate falls within given hour, day or week

I need to take a stored NSDate and reliably determine whether it falls within the current moment's hour, day or week. I seem to have hacked together a solution, but not having solved this problem before, am not entirely confident that it's a reliable one.
Will this survive user-set 12 vs 24 hour time? the date formatting guide indicates that this user setting can lead to some unanticipated date behavior: "In iOS, the user can override the default AM/PM versus 24-hour time setting. This may cause NSDateFormatter to rewrite the format string you set."
What about the basic code pattern for this problem? Does this code seem to reliably serve its purpose? I hate to post a "check my code" sort of question, but it's an unfamiliar-enough problem to me, and tricky enough to rigorously test, that it seemed justified. NSDateFormatter is also relatively new to me; another motivation for the question.
NOTE: The main source of my nervousness is that converting dates to strings and then doing a string compare seems an inherently fragile method of solving this problem. But it's the best I could come up with.
Quick reference: the dateFormats I used for each of the three cases were:
dateFormat = #"yyyyMMddHH"; // For "this hour" check
dateFormat = #"yyyyMMdd"; // For "today" check
dateFormat = #"yyyyww"; // For "this week" check
Thanks! Code Follows:
- (BOOL)didThisCycle {
// Case 1: hourly; Case 2: daily; Case 3: weekly
BOOL did = NO;
NSDate *now = [NSDate date];
NSDate *lastDid = [self.didDates lastObject];
if (![lastDid isKindOfClass:[NSDate class]]) { // Crash protection
return NO;
}
int type = [self.goalType intValue];
switch (type) {
case 1:
{
// If hourly check hour
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
formatter.dateFormat = #"yyyyMMddHH";
NSString *nowString = [formatter stringFromDate:now];
NSString *lastDidString = [formatter stringFromDate:lastDid];
if ([nowString isEqualToString:lastDidString]) {
did = YES;
} else {
did = NO;
}
break;
}
case 2:
{
// If daily check day
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
formatter.dateFormat = #"yyyyMMdd";
NSString *nowString = [formatter stringFromDate:now];
NSString *lastDidString = [formatter stringFromDate:lastDid];
if ([nowString isEqualToString:lastDidString]) {
did = YES;
} else {
did = NO;
}
break;
}
case 3:
{
// If weekly check week
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
formatter.dateFormat = #"yyyyww";
NSString *nowString = [formatter stringFromDate:now];
NSString *lastDidString = [formatter stringFromDate:lastDid];
if ([nowString isEqualToString:lastDidString]) {
did = YES;
} else {
did = NO;
}
break;
}
default:
{
did = NO;
break;
}
}
return did;
}
Use the NSDateComponents class, like so:
NSDate *someDate = // whatever
NSDate *now = [NSDate date];
NSDateComponents *thenComponents = [[NSCalendar currentCalendar] components:NSHourCalendarUnit|NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:someDate];
NSDateComponents *nowComponents = [[NSCalendar currentCalendar] components:NSHourCalendarUnit|NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:now];
if([thenComponents year] == [nowComponents year] && [thenComponents month] == [nowComponents month] && [thenComponents day] == [nowComponents day] && [thenComponents hour] == [nowComponents hour])
{
// hooray
}
Remove the “hour” component if you just want to check the day, or remove both that and “day” (and replace with NSWeekCalendarUnit and the -week method) to check the week.

How do I pause a stopwatch, then have it pick back up from where it started?

I am designing a timer that I want to be able to pause and continue from the same place. I tried doing it but the code wouldn't work for me. Here is my code:
.m file:
-(IBAction)buttonPause:(id)sender {
NSString *dateString = timer.text;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm:ss.SS"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:dateString];
dateFromString = startDate;
}
- (IBAction)buttonStart:(id)sender {
startDate = [NSDate date];
stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/100.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
}
- (void)updateTimer{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm:ss.SS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString = [dateFormatter stringFromDate:timerDate];
timer.text = timeString;
}
My problem appears to lie in the buttonPause method. What am I doing wrong or am not doing? Thank you in advanced.
You can use NSTimeInterval instead of timer. I have a functional code to pause and stop the timer.
#interface PerformBenchmarksViewController () {
int currMinute;
int currSecond;
int currHour;
int mins;
NSDate *startDate;
NSTimeInterval secondsAlreadyRun;
}
#end
- (void)viewDidLoad
{
[super viewDidLoad];
running = false;
}
- (IBAction)StartTimer:(id)sender {
if(running == false) {
//start timer
running = true;
startDate = [[NSDate alloc] init];
startTime = [NSDate timeIntervalSinceReferenceDate];
[sender setTitle:#"Pause" forState:UIControlStateNormal];
[self updateTime];
}
else {
//pause timer
secondsAlreadyRun += [[NSDate date] timeIntervalSinceDate:startDate];
startDate = [[NSDate alloc] init];
[sender setTitle:#"Start" forState:UIControlStateNormal];
running = false;
}
}
- (void)updateTime {
if(running == false) return;
//calculate elapsed time
NSTimeInterval currentTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval elapsed = secondsAlreadyRun + currentTime - startTime;
// extract out the minutes, seconds, and hours of seconds from elapsed time:
int hours = (int)(mins / 60.0);
elapsed -= hours * 60;
mins = (int)(elapsed / 60.0);
elapsed -= mins * 60;
int secs = (int) (elapsed);
//update our lable using the format of 00:00:00
timerLabel.text = [NSString stringWithFormat:#"%02u:%02u:%02u", hours, mins, secs];
//call uptadeTime again after 1 second
[self performSelector:#selector(updateTime) withObject:self afterDelay:1];
}
Hope this will help. Thanks

iPhone simple method definition and calling the current date/time

I'm very new to iPhone development, and I'm trying to write a function which will accept one parameter, and return the current date/month and store it in a variable.
But I'm getting a (null) value with NSLog.
Method:
-(NSString *) getNowDateMonth:(NSString *)type {
NSDate *now = [[NSDate alloc] init];
if (type==#"month") {
NSDateFormatter *monthFormat = [[NSDateFormatter alloc] init];
[monthFormat setDateFormat:#"MM"];
NSString *theMonth = [monthFormat stringFromDate:now];
[monthFormat release];
return theMonth;
} else if (type==#"day") {
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"dd"];
NSString *theDate = [dateFormat stringFromDate:now];
//int setDate = theDate;
[dateFormat release];
return theDate;
}
[now release];
return NULL;
}
Calling the function to get value:
NSString *month = [self getNowDateMonth:#"month"];
NSLog(#"%#", month);
Am I going about this the right way?
First of all, compare the strings using [#"month" isEqualToString:type], because two strings containing the same text ("month") may not be equal by the == operator. == checks if they're the same string object, not strings object with the same contents.
Second of all, you're leaking the date when returning the month or day (not releasing now). You should use [NSDate date]; instead of [[NSDate alloc] init].
To sum up, a suggested better version of this method would be:
-(NSString *) getNowDateMonth:(NSString *)type {
NSDate *now = [NSDate date];
if ([#"month" isEqualToString:type]) {
NSDateFormatter *monthFormat = [[NSDateFormatter alloc] init];
[monthFormat setDateFormat:#"MM"];
NSString *theMonth = [monthFormat stringFromDate:now];
[monthFormat release];
return theMonth;
} else if ([#"day" isEqualToString:type]) {
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"dd"];
NSString *theDate = [dateFormat stringFromDate:now];
[dateFormat release];
return theDate;
} else {
return nil;
}
}
Also, there are a few other points that can be taken into consideration to improve this method:
do not use NSString as type; use an enum
do not allocate NSDateFormatter on each call to the method; instead use a static variable in the method
You want to use NSDateComponents to reliably and easily extract unit information i.e. month, day, week etc from an NSDate.
See Date and Time Programming Guide for Cocoa.
Dates are a deceptively complex programing problem so Cocoa has a fully developed set of classes for dealing with them. However, the learning curve is a bit steep.