6

I want to setup some local notifications in my iOS app, however every tutorial I seem to find on implementing these seems to only allow me to fire a notification based on a timer (see sample code below)? Is it possible to fire a local notification for example when new data is loaded to a UITableView? Sorry for the general question, but I can't seem to find a whole lot of documentation on this. I'm also not sure how I could do this if data is only grabbed when my user hits a screen? E.g. data is grabbed/updated in viewDidLoad of ViewController?

-(void)viewDidLoad {

        UILocalNotification *localNotification = [[UILocalNotification alloc] init];
        localNotification.fireDate = dateTime;
        localNotification.alertBody = [NSString stringWithFormat:@"Alert Fired at %@", dateTime];
        localNotification.soundName = UILocalNotificationDefaultSoundName;
        localNotification.applicationIconBadgeNumber = 1;
        [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];

    }
Brittany
  • 1,359
  • 4
  • 24
  • 63
  • "new data is loaded"<-- use completionHandler for the [NSUrlSession](http://stackoverflow.com/questions/26174692/how-to-get-data-from-blocks-using-nsurlsession) also see [this tutorial](https://www.raywenderlich.com/110458/nsurlsession-tutorial-getting-started). Once the UrlRequest is *completed* you can do something... "When the button is pressed" <--That' basically you placing an **action** ( like a function...here your function would run a localNotification like you want) on a **target** (the button) <-- see [here](http://stackoverflow.com/questions/11939772/add-target-for-uibutton-ios) – mfaani Mar 28 '17 at 16:39
  • if you want to fire it at somepoint like when the loading is completed, on the loadings void you were created for the loading. create a Local Notification there, i am sorry if this not helps, but i dont get your question clearly – excitedmicrobe Mar 28 '17 at 16:46
  • Can you please clarify a couple of things: 1) Is the event you wish to notify on related to data becoming visible on screen (i.e. the UI event is the important event), the completion of e.g. a network data fetch (i.e. the data availability is the important event), or something else? 2) What, specifically, is the purpose of the notification? Is it simply to inform the user that the operation has completed, and if so, what specifically do they need to know? 3) Do you want to be able to inform them of this event when/if the app is in the background or only in the foreground? – fullofsquirrels Apr 06 '17 at 15:33
  • The use of a UILocalNotification is to fire a notification locally at a specific time. These notifications are aimed at alerting the user to an event while the app is not running or is minimised. UILocalNotifications do not display while the app is running (hence why you set a delay). The scenario you are describing sounds more like you should be looking at the NSNotificationCenter to fire Notifications to observer within your application. – Matthew Cawley Apr 10 '17 at 21:40

5 Answers5

4

First of all you should consider the fact that UILocalNotification class that you are using is deprecated starting from iOS 10. Since iOS 10 there is no distinction between local and remote notifications.

In UserNotifications framework (iOS 10.0+, Swift | Objective-C) one does not create instances of UNNotification like in some of the previous implementations of similar frameworks / API's by Apple. Instead, an instance of UNNotificationCenter is responsible for creating notification objects and calls delegate methods when new notifications are received and before the default UI will be displayed. See Apple's documentation for more details on the requirements for conforming UNUserNotificationCenterDelegate protocol. I often end up using AppDelegate as a class conforming to that protocol

Now back to the question. To initiate a creation of the notification from within the app first you should create a trigger (in your case you might want to use UNTime​Interval​Notification​Trigger), then create a notification request and finally add the request to the notification center singleton that can be accessed by calling UNUserNotificationCenter.current().

let content = UNMutableNotificationContent()
content.title = "Alert Fired"

Create a trigger that will determine the moment when UNUserNotificationCenter will invoke the notification

let trigger = UNTime​Interval​Notification​Trigger(timeInterval: 0, repeats: false)

Create a notification request. You only create those to invoke local notifications, since iOS is responsible for creating request objects for incoming push notifications.

let request = UNNotificationRequest(identifier: "FiveSecond", content: content, trigger: trigger)

Now we will have to add our request to the current notification center associated with our app.

let center = UNUserNotificationCenter.current()
center.add(request, withCompletionHandler: nil)

In our case the notification will be triggered immediately by the UNUserNotificationCenter.

  • I'm not coding with Swift, I'm using Obj-C. Do you have this solution for obj-c? – Brittany Mar 28 '17 at 17:26
  • Also: This method still uses a timer? – Brittany Mar 28 '17 at 18:02
  • 1
    @Brittany Yes, if you are developing for iOS 10 all the apis are available in both Swift & Obj-C. I can post an answer in Obj-C as well but I encourage you to read [UserNotification documentation](https://developer.apple.com/reference/usernotifications?language=objc) first. – Kirill Dubovitskiy Mar 29 '17 at 21:29
  • To trigger notification immediately you should use 'trigger: nil' in request – dandepeched Mar 12 '19 at 14:20
3

You can use the method postNotificationName like this:

MyCustomObject *customObject = [MyCustomObject new];
[[NSNotificationCenter defaultCenter] postNotificationName:@"Your notification name" object:customObject];

Processing the object coming through from the posted notification would look something like this. Obviously, I am only logging here but you can process it whatever way you like.

- (void)methodToProcessNotificationData:(NSNotification *)notification {
   NSLog(@"%@",notification.object);
}

When you want a class to listen for the notification you can do something like the below chunk of code. This adds the observer to the class, gives it the method that is to be called (in this instance methodToProcessNotificationData) and the notification name that you wish to listen out for.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(methodToProcessNotificationData:) name:@"Your notification name" object:nil];
HarmVanRisk
  • 203
  • 1
  • 8
  • I don't have an official source but I work as an iOS developer. This answer is constructed based on my experience with Notifications – HarmVanRisk Apr 06 '17 at 12:56
1

You can use below method[1] instead:

- (void)postNotificationName:(NSNotificationName)aName 
                      object:(id)anObject 
                    userInfo:(NSDictionary *)aUserInfo;

[1]https://developer.apple.com/reference/foundation/nsnotificationcenter/1410608-postnotificationname?language=objc

jokeman
  • 1,277
  • 9
  • 22
  • So NSNotificationName would be whatever I name the notification in my code above, yes? And where would "anObject" data come from/what would it be for example? – Brittany Mar 28 '17 at 16:52
  • @Brittany If you want to send some data to the subscriber of the notification, then you can pass that in userInfo. – jokeman Mar 28 '17 at 17:02
  • @Brittany (NSNotificationName)aName is the name of the notification you want to post. Then you subscribe this notification with the same name – jokeman Mar 28 '17 at 17:04
  • @Brittany see [Fundamentals of callback](https://www.andrewcbancroft.com/2016/02/15/fundamentals-of-callbacks-for-swift-developers/). This solution only works for your button logic. doesn't work if you want to do something **after** data is loaded – mfaani Mar 28 '17 at 17:30
1

You can simply give The time as [NSDate date] whenever you want to fire local notification. It will fire a notification at current time.

Raza.najam
  • 769
  • 6
  • 15
0

first thing in mind for what ios you need local local notification

// Handle launching from a notification

if(IOS_VERSION<10)
{
    UILocalNotification *locationNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
    if (locationNotification)
 {
    // Set icon badge number to zero
    application.applicationIconBadgeNumber = 0;
}

if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)])
{

    [application registerUserNotificationSettings:[UIUserNotificationSettings
                                                   settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|
                                                   UIUserNotificationTypeSound categories:nil]];
}

}else{

[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound)
                                                                    completionHandler:^(BOOL granted, NSError * _Nullable error) {
                                                                        // Enable or disable features based on authorization.
                                                                    }];

}

and final thing

    if(IOS_VERSION<10){

        [[UIApplication sharedApplication] cancelAllLocalNotifications];

        NSLog(@"LocalNotifications]count %d",(int) [[[UIApplication sharedApplication] scheduledLocalNotifications]count]);

        NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar] ;
        NSDate *now = [NSDate date];
        NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth |  NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:now];
        [components setHour:15];
        [components setMinute:35];

        UILocalNotification *notification = [[UILocalNotification alloc]init];
        notification.fireDate = [calendar dateFromComponents:components];
        notification.repeatInterval = NSCalendarUnitDay;
        notification.alertBody =@"message";
        notification.applicationIconBadgeNumber = 0;
        notification.soundName = UILocalNotificationDefaultSoundName;
        [[UIApplication sharedApplication] scheduleLocalNotification:notification];


    }else{

        [[UNUserNotificationCenter currentNotificationCenter] removeAllPendingNotificationRequests];
        NSLog(@"LocalNotifications]count %d",(int) [[[UIApplication sharedApplication] scheduledLocalNotifications]count]);

        NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar] ;
        NSDate *now = [NSDate date];
        NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth |  NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:now];
        [components setHour:15];
        [components setMinute:35];




        UNMutableNotificationContent *objNotificationContent = [[UNMutableNotificationContent alloc] init];
//        objNotificationContent.title = [NSString localizedUserNotificationStringForKey:NotificationHeading arguments:nil];
        objNotificationContent.body = [NSString localizedUserNotificationStringForKey:@"message"
                                                                            arguments:nil];
        objNotificationContent.sound = [UNNotificationSound defaultSound];

        /// 4. update application icon badge number
        objNotificationContent.badge = @([[UIApplication sharedApplication] applicationIconBadgeNumber]);

//        UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
//                                                      triggerWithTimeInterval:60 repeats:YES];

        UNCalendarNotificationTrigger *trigger2 = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:YES];

        UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"FiveSecond"
                                                                              content:objNotificationContent trigger:trigger2];

        /// 3. schedule localNotification
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];


        [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
            if (!error) {
                NSLog(@"Local Notification succeeded");
            }
            else {
                NSLog(@"Local Notification failed");
            }
        }];


    }
Jagveer Singh
  • 2,258
  • 19
  • 34