Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS UILocalNotification set to fire once every day, once every two days, and only on Sundays

I'm trying to use a settings bundle to schedule a UILocalNotification. In settings, you can choose if you want the notifications to come daily (1/day), 1 every 2 days, only on Sundays or never.

Here is the code I used (this is all in AppDelegate.m):

    -(void)defaultsChanged:(NSNotification *)notification {

         [[UIApplication sharedApplication] cancelAllLocalNotifications];

        [[NSUserDefaults standardUserDefaults]synchronize];
        NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:@"multi_preference"];

        NSLog(@"%@", testValue);

        NSDate *today = [NSDate date];

        NSCalendar* calendar = [NSCalendar currentCalendar];
        NSDateComponents* compoNents = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:today]; // Get necessary date components

        [compoNents month];[compoNents day];

        NSDictionary *dictToday= [self getDataFromdate : [compoNents day] month:[compoNents month]];


        if ([testValue isEqualToString:@"one"]){
            UILocalNotification* localNotification = [[UILocalNotification alloc] init];
            localNotification.fireDate = [[NSDate date]dateByAddingTimeInterval:20];
            localNotification.alertAction = @"View";
            localNotification.alertBody = [dictToday objectForKey:@"saint_description"];
            localNotification.repeatInterval = NSDayCalendarUnit;
            localNotification.timeZone = [NSTimeZone defaultTimeZone];
            localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;

            [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
             [[NSNotificationCenter defaultCenter] postNotificationName:@"reloadData" object:self];

             }
        if (testValue==Nil){
            UILocalNotification* localNotification = [[UILocalNotification alloc] init];
            localNotification.fireDate = [[NSDate date]dateByAddingTimeInterval:20];
            localNotification.alertAction = @"View";
            localNotification.alertBody = [dictToday objectForKey:@"saint_description"];
            localNotification.repeatInterval = NSDayCalendarUnit;
            localNotification.timeZone = [NSTimeZone defaultTimeZone];
            localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;

            [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"reloadData" object:self];

        }
        if ([testValue isEqualToString:@"two"]){

            UILocalNotification* localNotification = [[UILocalNotification alloc] init];
            localNotification.fireDate = [[NSDate date]dateByAddingTimeInterval:86401];
            localNotification.alertAction = @"View";
            localNotification.alertBody = [dictToday objectForKey:@"saint_description"];
            localNotification.repeatInterval = NSDayCalendarUnit;
            localNotification.timeZone = [NSTimeZone defaultTimeZone];
            localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;

            [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
             [[NSNotificationCenter defaultCenter] postNotificationName:@"reloadData" object:self];

        }

        if ([testValue isEqualToString:@"three"]){
        NSDate *today2 = [[NSDate alloc] init];
        NSCalendar *gregorian = [[NSCalendar alloc]
                                 initWithCalendarIdentifier:NSGregorianCalendar];

        // Get the weekday component of the current date
        NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit
                                                           fromDate:today2];

        /*
         Create a date components to represent the number of days to subtract from the current date.
         The weekday value for Sunday in the Gregorian calendar is 1, so subtract 1 from the number of days to subtract from the date in question.  (If today is Sunday, subtract 0 days.)
         */
        NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
        [componentsToSubtract setDay: 0 - ([weekdayComponents weekday] - 1)];

        NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract
                                                             toDate:today2 options:0];

        /*
         Optional step:
         beginningOfWeek now has the same hour, minute, and second as the original date (today).
         To normalize to midnight, extract the year, month, and day components and create a new date from those components.
         */
        NSDateComponents *components =
        [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit |
                               NSDayCalendarUnit) fromDate: beginningOfWeek];
        beginningOfWeek = [gregorian dateFromComponents:components];



            UILocalNotification* localNotification = [[UILocalNotification alloc] init];
            localNotification.fireDate = beginningOfWeek;
            localNotification.alertAction = @"View";
            localNotification.alertBody = [dictToday objectForKey:@"saint_description"];
            localNotification.repeatInterval = NSWeekdayCalendarUnit;
            localNotification.timeZone = [NSTimeZone defaultTimeZone];
            localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;

            [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
            [[NSNotificationCenter defaultCenter] postNotificationName:@"reloadData" object:self];

        }
    }

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(defaultsChanged:)
                                                 name:NSUserDefaultsDidChangeNotification
                                               object:nil];

    UILocalNotification *locationNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
    if (locationNotification) {
        // Set icon badge number to zero
        application.applicationIconBadgeNumber = 0;
    }
return yes;
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{




    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Today's Saint"
                                                    message:notification.alertBody
                                                   delegate:self cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    if (notification.alertBody!=Nil)
    [alert show];


     [[NSNotificationCenter defaultCenter] postNotificationName:@"reloadData" object:self];

    // Set icon badge number to zero
    application.applicationIconBadgeNumber = 0;
}

Is the code correct for launching the notifications as I've stated? If not, what's the problem with it? Thanks!

like image 899
George Ciobanu Avatar asked Oct 31 '13 10:10

George Ciobanu


1 Answers

It seems you are scheduling notifications whenever the user changes preferences. However, you never unschedule previously scheduled notifications, which is why you are observing bursts of notifications at times that will correspond exactly to the times you repeatedly changed settings a day or two days ago.

The notifications you schedule are different objects than the set of notifications that you intend to modify. Unfortunately, UILocalNotifications have no identifier tokens.

However, you can unschedule all previous notifications whenever you receive a defaultsChanged: message with [[UIApplication sharedApplication] cancelAllLocalNotifications]; before you reschedule. This will solve your problem.

Also have a close look at this solution which suggests to cancel and reschedule notifications even upon launch to avoid bursts or duplicate notifications when a user re-installs your app.

like image 129
s.bandara Avatar answered Nov 13 '22 02:11

s.bandara