预定的本地通知是不规则的
Scheduled local notifications are irregular
我的 iOS 本地通知遇到了很大的问题。我有一个用 Objective-C 编写的应用程序,它允许用户选择通知触发的时间,以及一周中的几天(它应该在每周的指定日期的指定时间触发)。我对一天中通知触发的时间没有问题,它工作正常。但是,当我指定它应该触发的日期时,会发生奇怪的事情。起初,他们开火一次,但每天开火,而不是仅在指定的日子开火。然后,在第一周之后,他们每天都开火,但不止一次。相反,它们会在指定的日期内触发多次(因此,如果选择星期日、星期一和星期二,则用户每天都会在指定时间收到 3 次连续通知)。
这是我用来设置通知的代码。
点击 "Save" 按钮后,首先发生的事情是清除 所有 通知,为新通知让路。
//cancels all notifications upon save
[[UIApplication sharedApplication] cancelAllLocalNotifications];
接下来,我使用 NSDate、NSCalendar 和 NSCalendarComponents 获取当前时间的具体信息,以及来自我的 UIPicker 的组件(用于 select 一天中的时间)
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitWeekOfYear|NSCalendarUnitWeekday|NSCalendarUnitHour|NSCalendarUnitMinute fromDate:now];//get the required calendar units
然后,我从 UIPicker 获取时间单位,从选择器获取实际时间。
NSDateComponents *pickedComponents = [calendar components:(NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:picker.date];
NSDate *minuteHour = [calendar dateFromComponents:pickedComponents];
[[NSUserDefaults standardUserDefaults] setObject:minuteHour forKey:@"FireTime"];
之后,我设置了我想在通知中显示的文本
NSString *reminder = @"Reminder text!";
接下来是通知的实际设置。它们都是一样的(当然,星期几改变了),所以我只显示星期天的那个。
//sunday
UILocalNotification *localNotificationSunday = [[UILocalNotification alloc] init];
if ([sundayTempStatus isEqual:@"1"])
{
//permanently save the status
[[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"Sunday"];
//set up notifications
//if it is past sunday, push next week
if (components.weekday > 1)
{
components.day = components.day + 7; //if already passed sunday, make it next sunday
}
//components.day = 1;
components.hour = [pickedComponents hour];
components.minute = [pickedComponents minute];
NSDate *fireDate = [calendar dateFromComponents:components];
localNotificationSunday.fireDate = fireDate;
localNotificationSunday.alertBody = reminder;
localNotificationSunday.timeZone = [NSTimeZone systemTimeZone];
localNotificationSunday.repeatInterval = NSCalendarUnitWeekOfYear;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotificationSunday];
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:@"0" forKey:@"Sunday"];
}
非常感谢任何帮助,如果需要任何其他信息或代码,我很乐意提供。
当代码变得重复时,它往往更容易出错。我写了一个简单的方法来安排提醒。
- (void)scheduleNotificationForDayOfWeek:(int)dayOfWeek withPickedComponents:(NSDateComponents *)pickedComponents andReminderString:(NSString *)reminderString {
NSCalendar *calendar = [NSCalendar currentCalendar];
UILocalNotification *notification = [[UILocalNotification alloc] init];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitWeekOfYear|NSCalendarUnitWeekday|NSCalendarUnitHour|NSCalendarUnitMinute fromDate:[NSDate date]];
components.hour = [pickedComponents hour];
components.minute = [pickedComponents minute];
NSDateComponents *additionalComponents = [[NSDateComponents alloc] init]; // to be added onto our date
if ([components weekday] < dayOfWeek) {
additionalComponents.day = (dayOfWeek - [components weekday]); // add the number of days until the next occurance of this weekday
} else if ([components weekday] > dayOfWeek) {
additionalComponents.day = (dayOfWeek - [components weekday] + 7); // add the number of days until the next occurance of this weekday
}
NSDate *fireDate = [calendar dateFromComponents:components];
fireDate = [calendar dateByAddingComponents:additionalComponents toDate:fireDate options:0]; // add on our days
notification.fireDate = fireDate;
notification.alertBody = reminderString;
notification.timeZone = [NSTimeZone systemTimeZone];
notification.repeatInterval = NSCalendarUnitWeekOfYear;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
这个的作用其实很简单。用星期几调用它(例如,0 = 星期日,1 = 星期一),它会为那一天安排重复提醒。我无法在我的测试中用你的星期日代码重现你的问题,所以我认为在重复该代码的某个地方你一定犯了一个错误。
在这个方法中,点火日期的获取得到了简化。它使用 NSDateComponents 轻松获取该工作日的下一次出现。像这样称呼它:[self scheduleNotificationForDayOfWeek:0 withPickedComponents:pickedComponents andReminderString:@"Hello, world!"];
(每个星期天在指定的组件显示 "Hello, world!")
使用此代码段,您应该能够摆脱代码中的大部分重复语句,并简化设置通知的方式。对我来说,这非常有效。
我的 iOS 本地通知遇到了很大的问题。我有一个用 Objective-C 编写的应用程序,它允许用户选择通知触发的时间,以及一周中的几天(它应该在每周的指定日期的指定时间触发)。我对一天中通知触发的时间没有问题,它工作正常。但是,当我指定它应该触发的日期时,会发生奇怪的事情。起初,他们开火一次,但每天开火,而不是仅在指定的日子开火。然后,在第一周之后,他们每天都开火,但不止一次。相反,它们会在指定的日期内触发多次(因此,如果选择星期日、星期一和星期二,则用户每天都会在指定时间收到 3 次连续通知)。
这是我用来设置通知的代码。
点击 "Save" 按钮后,首先发生的事情是清除 所有 通知,为新通知让路。
//cancels all notifications upon save
[[UIApplication sharedApplication] cancelAllLocalNotifications];
接下来,我使用 NSDate、NSCalendar 和 NSCalendarComponents 获取当前时间的具体信息,以及来自我的 UIPicker 的组件(用于 select 一天中的时间)
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitWeekOfYear|NSCalendarUnitWeekday|NSCalendarUnitHour|NSCalendarUnitMinute fromDate:now];//get the required calendar units
然后,我从 UIPicker 获取时间单位,从选择器获取实际时间。
NSDateComponents *pickedComponents = [calendar components:(NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:picker.date];
NSDate *minuteHour = [calendar dateFromComponents:pickedComponents];
[[NSUserDefaults standardUserDefaults] setObject:minuteHour forKey:@"FireTime"];
之后,我设置了我想在通知中显示的文本
NSString *reminder = @"Reminder text!";
接下来是通知的实际设置。它们都是一样的(当然,星期几改变了),所以我只显示星期天的那个。
//sunday
UILocalNotification *localNotificationSunday = [[UILocalNotification alloc] init];
if ([sundayTempStatus isEqual:@"1"])
{
//permanently save the status
[[NSUserDefaults standardUserDefaults] setObject:@"1" forKey:@"Sunday"];
//set up notifications
//if it is past sunday, push next week
if (components.weekday > 1)
{
components.day = components.day + 7; //if already passed sunday, make it next sunday
}
//components.day = 1;
components.hour = [pickedComponents hour];
components.minute = [pickedComponents minute];
NSDate *fireDate = [calendar dateFromComponents:components];
localNotificationSunday.fireDate = fireDate;
localNotificationSunday.alertBody = reminder;
localNotificationSunday.timeZone = [NSTimeZone systemTimeZone];
localNotificationSunday.repeatInterval = NSCalendarUnitWeekOfYear;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotificationSunday];
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:@"0" forKey:@"Sunday"];
}
非常感谢任何帮助,如果需要任何其他信息或代码,我很乐意提供。
当代码变得重复时,它往往更容易出错。我写了一个简单的方法来安排提醒。
- (void)scheduleNotificationForDayOfWeek:(int)dayOfWeek withPickedComponents:(NSDateComponents *)pickedComponents andReminderString:(NSString *)reminderString {
NSCalendar *calendar = [NSCalendar currentCalendar];
UILocalNotification *notification = [[UILocalNotification alloc] init];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitWeekOfYear|NSCalendarUnitWeekday|NSCalendarUnitHour|NSCalendarUnitMinute fromDate:[NSDate date]];
components.hour = [pickedComponents hour];
components.minute = [pickedComponents minute];
NSDateComponents *additionalComponents = [[NSDateComponents alloc] init]; // to be added onto our date
if ([components weekday] < dayOfWeek) {
additionalComponents.day = (dayOfWeek - [components weekday]); // add the number of days until the next occurance of this weekday
} else if ([components weekday] > dayOfWeek) {
additionalComponents.day = (dayOfWeek - [components weekday] + 7); // add the number of days until the next occurance of this weekday
}
NSDate *fireDate = [calendar dateFromComponents:components];
fireDate = [calendar dateByAddingComponents:additionalComponents toDate:fireDate options:0]; // add on our days
notification.fireDate = fireDate;
notification.alertBody = reminderString;
notification.timeZone = [NSTimeZone systemTimeZone];
notification.repeatInterval = NSCalendarUnitWeekOfYear;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
这个的作用其实很简单。用星期几调用它(例如,0 = 星期日,1 = 星期一),它会为那一天安排重复提醒。我无法在我的测试中用你的星期日代码重现你的问题,所以我认为在重复该代码的某个地方你一定犯了一个错误。
在这个方法中,点火日期的获取得到了简化。它使用 NSDateComponents 轻松获取该工作日的下一次出现。像这样称呼它:[self scheduleNotificationForDayOfWeek:0 withPickedComponents:pickedComponents andReminderString:@"Hello, world!"];
(每个星期天在指定的组件显示 "Hello, world!")
使用此代码段,您应该能够摆脱代码中的大部分重复语句,并简化设置通知的方式。对我来说,这非常有效。