"Invalid date component" error when set startDateComponents in an EKReminder - iphone

I want to save a reminder, but when I set the StartDateComponents, it always says Invalid date component. I try several ways(you can see my commented code) to set the value, but failed.
EKReminder *reminder = [EKReminder reminderWithEventStore:appDelete.eventStore];
NSCalendar *gregorian = [NSCalendar currentCalendar];//[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
reminder.title = #"title";
NSString *timeStr = #"20121115070800";
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
[inputFormatter setCalendar:gregorian];
[inputFormatter setDateFormat:#"yyyyMMddHHmmss"];
[inputFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSDate *parseDate = [inputFormatter dateFromString:timeStr];
NSDateComponents *dateComponents = [gregorian components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:parseDate];
NSDateComponents *timeComponents = [gregorian components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:parseDate];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
// Notification will fire in one minute
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:[timeComponents second]];
[dateComps setTimeZone:[NSTimeZone localTimeZone]];
reminder.calendar = /*[NSCalendar autoupdatingCurrentCalendar];*/[eventStore defaultCalendarForNewEvents];
reminder.calendar = [EKCalendar calendarWithEventStore:eventStore];
//NSDateComponents *comp = [[NSDateComponents alloc] init];
/*comp.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
comp.year = [[timeStr substringToIndex:3] integerValue];
comp.month = [[timeStr substringWithRange:NSMakeRange(4,2)] integerValue];
comp.day = [[timeStr substringWithRange:NSMakeRange(6, 2)] integerValue];
comp.hour = [[timeStr substringWithRange:NSMakeRange(8, 2)] integerValue];
comp.minute = [[timeStr substringWithRange:NSMakeRange(10, 2)] integerValue];
comp.second = [[timeStr substringWithRange:NSMakeRange(12, 2)] integerValue];*/
//reminder.startDateComponents = [gregorian components: (NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit/*|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit*/) fromDate:parseDate];
[reminder setStartDateComponents:dateComps];// this line will throw the error:Invalid date component

It seemed the main issue was these 2 lines:
reminder.calendar = /*[NSCalendar autoupdatingCurrentCalendar];*/[eventStore defaultCalendarForNewEvents];
reminder.calendar = [EKCalendar calendarWithEventStore:eventStore];
Replace with this line:
reminder.calendar = [eventStore defaultCalendarForNewReminders];
Here are the complete working code that also included a little extra for completeness:
EKEventStore *eventStore = [[EKEventStore alloc] init];
[eventStore requestAccessToEntityType:EKEntityMaskEvent completion:^(BOOL granted, NSError *error) {
if (granted)
{
EKReminder *reminder = [EKReminder reminderWithEventStore:eventStore];
NSCalendar *gregorian = [NSCalendar currentCalendar];//[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
reminder.title = #"title44433333";
NSString *timeStr = #"20121115070800";
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
[inputFormatter setCalendar:gregorian];
[inputFormatter setDateFormat:#"yyyyMMddHHmmss"];
[inputFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSDate *parseDate = [inputFormatter dateFromString:timeStr];
NSDateComponents *dateComponents = [gregorian components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:parseDate];
NSDateComponents *timeComponents = [gregorian components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:parseDate];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
// Notification will fire in one minute
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:[timeComponents second]];
[dateComps setTimeZone:[NSTimeZone localTimeZone]];
reminder.calendar = [eventStore defaultCalendarForNewReminders]; //here is the replacement
[reminder setStartDateComponents:dateComps];// this line will throw the error:Invalid date component
NSError *error = nil;
[eventStore saveReminder:reminder commit:YES error:&error];
if (error) NSLog(#"error = %#", error);
}
}];

Related

Local Notification only firing once?

I have a local notification set to fire on the specified date when a user changes the date
on a UIDatePicker. However, when I ran the app, the notification fired correctly, but when
I went and made a small change, then ran it again, the notification didn't fire. Here's my
code, please help!
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
// Get the current date
NSDate *pickerDate = [datepicker date];
// Break the date up into components
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:pickerDate];
NSDateComponents *timeComponents = [calendar components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:pickerDate];
// Set up the fire time
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:[timeComponents second]];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
[dateComps release];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = itemDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
// Notification details
localNotif.alertBody = #"Timer";
// Set the action button
localNotif.alertAction = #"View";

Issue with canceling UILocaleNotification

I have created a locale notification for my application which fires every day , also in apple developer documentation mentioned that you can fire only 64 notifications , so my question is how can I prevent this limitation ? I mean my notification scheduled that fires everyday per a year , so is this right way to cancel notification and then fires again with scheduled plan ?
- (void)cancelLocalNotification:(UILocalNotification *)notification {
[[UIApplication sharedApplication] cancelLocalNotification:notification;
}
here is my Notification code :
- (void) notification {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSPersianCalendar];
NSDate *now = [NSDate date];
NSDateComponents *componentsForFireDate = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit ) fromDate: now];
[componentsForFireDate year];
[componentsForFireDate month];
[componentsForFireDate day];
[componentsForFireDate setHour:1];
[componentsForFireDate setMinute:2];
[componentsForFireDate setSecond:1];
NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
UILocalNotification *notification = [[UILocalNotification alloc]init];
notification.fireDate = fireDateOfNotification;
notification.timeZone = [NSTimeZone localTimeZone];
notification.repeatInterval= NSDayCalendarUnit;
notification.alertAction = #"View";
notification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
Read your problem here. it surely solved ur problem Repeating an iOS local notification
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *pickerDate = [self.datePicker date];
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:pickerDate];
NSDateComponents *timeComponents = [calendar components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:pickerDate];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:[timeComponents second]];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = itemDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = [eventText text];
localNotif.alertAction = #"View";
localNotif.soundName = audios;
localNotif.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
[localNotif release];

Getting NSDate from a UIPickerView

I have a picker view similar to the alarm clock app on the iphone (first component = 1-12, second component = 0-60, third component = am/pm). What I do is this in the didSelect delegate of the picker view.
if (component == PICKER_HOURS) {
rowSelected = [self.hour objectAtIndex:row % 12];
self.hourSelected = rowSelected;
}
else if (component == PICKER_MINUTES) {
rowSelected = [self.minutes objectAtIndex:row % 60];
self.minuteSelected = rowSelected;
}
else {
rowSelected = [self.ampm objectAtIndex:row];
self.ampmSelected = rowSelected;
}
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
dateFormatter.dateFormat = #"h:mm a";
NSString *timeString = [NSString stringWithFormat:#"%#:%# %#", _hourSelected, _minuteSelected, _ampmSelected];
NSString *trimmedTimeString = [timeString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSDate *dateSelected = [dateFormatter dateFromString:timeString];
NSDate *dateForAlarm = [self alarmDateForDate:dateSelected];
------
- (NSDate *)alarmDateForDate:(NSDate *)dateSelected {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:[NSDate date]]; // set the date to the current date
NSDateComponents *timeComponents = [calendar components:(NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:dateSelected]; // set the time to what's in the picker
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setYear:[dateComponents year]];
[dateComps setMonth:[dateComponents month]];
[dateComps setHour:[timeComponents hour]];
[dateComps setMinute:[timeComponents minute]];
NSDate *dateForAlarm = [calendar dateFromComponents:dateComps];
return dateForAlarm;
}
Is this the right approach? I realized that my dateFromString in the picker view is always the 1970 time. So I wasn't sure if this was 'standard' way to get the time from a picker view so that it is in the future to set a notification. Thanks!
Look at this -
Date Picker :-
m_pDatePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 40, 50, 50)];
m_pDatePicker.datePickerMode = UIDatePickerModeDate;
NSDate *minDate = [NSDate new];
[m_pDatePicker setMinimumDate:minDate];
m_pDatePicker.hidden = NO;
[m_pClientView addSubview:m_pDatePicker];
[m_pDatePicker addTarget:self action:#selector(pickDateLabel)forControlEvents:UIControlEventValueChanged];
NSDateComponents* comps = [m_pDatePicker.calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:m_pDatePicker.date];
int myDay = [comps day];
int myMonth = [comps month];
int myYear = [comps year];
pickDateLabel.text=[NSString stringWithFormat:#"%d/%d/%d",myMonth,myDay,myYear];
dueDateLabel.text=[NSString stringWithFormat:#"%d/%d/%d",myDay,myMonth,myYear];
[m_pDatePicker release];
[minDate release];
}
Picking Date -
- (void)pickDateLabel
{
NSDateComponents* comps = [m_pDatePicker.calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:m_pDatePicker.date];
int myDay = [comps day];
int myMonth = [comps month];
int myYear = [comps year];
pickDateLabel.text=[NSString stringWithFormat:#"%d/%d/%d",myMonth,myDay,myYear];
dueDateLabel.text=[NSString stringWithFormat:#"%d/%d/%d",myDay,myMonth,myYear];
}
Hope it helps !!

iOS: Date Components Inquiry

I was wondering how I would edit the dateComps setDay: to go off 3 days before the date set in the picker. I typed in -3, but that doesn't seem to do the trick.
Any help is much appreciated! Here is my code:
- (IBAction)scheduleNotifButton:(id)sender {
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *pickerDate = [self.datePicker date];
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:pickerDate];
NSDateComponents *timeComponents = [calendar components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:pickerDate];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:13];
[dateComps setMinute:30];
[dateComps setSecond:[timeComponents second]];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = itemDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = #"Event is in 3 days!";
localNotif.alertAction = nil;
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber = 0;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
When you say you have typed -3, do you mean you used this line?
[dateComps setDay:[dateComponents day] - 3];
This should in fact work.
Also, you can tell the system to fire any next year by just settings the current year to the date components. You can find the current year just the way you found the date components for pickerDate.
After that, you can set the repeatInterval of the local notification to NSYearCalendarUnit, that way it will fire each year.
Here is a code to subtract 3 days from Today(NOW). You can adapt it for your needs:
NSDate *today = [NSDate date];
NSLog(#"NOW:%#",today);
NSCalendar *gregorian = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *todayComps = [gregorian components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit |NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:today];
todayComps.day -=3;
NSDate *dateMinus3Days = [gregorian dateFromComponents:todayComps];
NSLog(#"3 days before NOW:%#",dateMinus3Days);
Your making it too complicated. DateComponents can be modified and then set to a new date.
I think all you need to do is subtract 3 days from the date returned by the date picker, no?
NSDate *pickerDate = [self.datePicker date]
pickerDate = [ pickerDate dateByAddingTimeInterval:-3 * 24 * 60 * 60 ] ; // add this line
Version using date components:
- (IBAction)scheduleNotifButton:(id)sender {
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *pickerDate = [self.datePicker date];
{
NSDateComponent * deltaComponents = [ [ NSDateComponents alloc ] init ];
deltaComponents.days = -3 ;
pickerDate = [ pickerDate dateByAddingComponents:deltaComponents ] ;
}
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit ) fromDate:pickerDate];
[dateComps setHour:13];
[dateComps setMinute:30];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = itemDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = #"Event is in 3 days!";
localNotif.alertAction = nil;
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber = 0;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
Use dateByAddingComponents:toDate:options:
// ...
NSDateComponents *offset = [NSDateComponents new];
[offset setDay:(-3)];
NSDate *date3DaysBefore = [calendar dateByAddingComponents:offset toDate:pickerDate options:0];
// ...

local notification not firing in iphone

This may be a repeated question,but please help me.I used the code below for firing a local notifification,but it is not firing.I used a picker to set the time for firing the local notification.Please help me..
[self.actionSheet dismissWithClickedButtonIndex:0 animated:YES];
if (nil != self.data) {
//send data picker message
[self.target performSelector:self.action withObject:[NSNumber numberWithInt:self.selectedIndex]];
}
else {
//NSDate *date = [NSDate date];
//NSDateFormatter *dateFormat = [[NSDateFormatter alloc]init];
//[dateFormat setDateFormat:#"HH:mm:ss zzz"];
//NSString *dateString = [dateFormat stringFromDate:date];
//send date picker message
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
// Get the current date
NSDate *pickerDate = [self.datePickerView date];
//NSLog(#"date ==%#",pickerdate);
//Break the date up into components
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:pickerDate];
NSDateComponents *timeComponents = [calendar components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:pickerDate];
// Set up the fire time
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
//NSLog(#"day%#",[dateComponents day]);
// Notification will fire in one minute
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:[timeComponents second]];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
[dateComps release];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = itemDate;
NSLog(#"%#what is this",itemDate);
localNotif.timeZone = [NSTimeZone defaultTimeZone];
//Notification details
localNotif.alertBody = #"Tip of the day";
//Set the action button
localNotif.alertAction = #"View";
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.repeatInterval = NSDayCalendarUnit;
localNotif.applicationIconBadgeNumber = 1;
// Specify custom data for the notification
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:#"someValue" forKey:#"someKey"];
localNotif.userInfo = infoDict;
// Schedule the notification
[localNotif release];
}
Where is the code for scheduling the local notification?
You have to make this call somewhere before you release your UILocalNotification object:
- (void)scheduleLocalNotification:(UILocalNotification *)notification
Like so,
[[UIApplication sharedApplication] scheduleLocalNotification: localNotif];
Its only after you call this method that your notification gets copied, and hence safe for releasing the notification object.