What is the best way to set up iOS local notifications using custom UIPickerViews?
As expert iOS app developers, we know iOS apps inside out. We’re always sharing tips for iOS app developers on our blog and answering your questions. So, when we were frequently asked about how to schedule local iOS notifications, we thought we’d write this article.
This blog looks at how we can use selected picker options to set the local notification to the required period.
In a previous blog, I walked through how we populated the UIPickerViews using enums, how we could link both pickers using enum associated values and how we could handle the selection of each picker using generic picker data sources. This blog is the second part of that guide.
User notifications on iOS come in 2 flavours: push notifications and local notifications. In this article, we will be focusing on local notifications. However, it’s helpful if you understand the difference between the two.
Push (or remote) notifications are generated from a server and use Apple Push Notification service (APNs) to deliver notifications to the user.
Local notifications are created by an app to show the notification when a specific condition is met (at a specific time or location).
The feature we want to build will allow the user to set up local push notifications on iOS. This could be achieved using push notifications that make an API call to our server to schedule the notification. The service then runs a task periodically to send a push notification back to the user's device at the required time.
This implementation, however, is far more complex and would require many more moving parts, building and maintaining a server (if not already needed by the app), adding a new API endpoint, adding the APNs capability to the app, setting up scheduled tasks in the server to send messages out for each user that wants to receive notifications. We can use local notifications to simplify all this and not require external servers.
The first step in creating local iOS notifications is to request permission from the user to send them notifications. This is achieved by:
We get the current User Notification centre. This object manages all the notification related activities for the app. We then request authorisation to send notifications with a set of options describing the type of notifications you want to send. Here we are requesting to display an alert, play a sound and update the app's badge.
If permission is granted, we can continue with setting up our reminder notifications, (any errors should be handled appropriately).
The code for setting up a local notification is fairly simple, there are three parts to a local notification, the content, trigger and request.
The content encompasses what is actually shown to the user. Text, sound, badge number, attachments (for rich content such as images) and user info might be used when interacting with the notification.
For the reminder notifications, we will only be setting the text of the notification. A basic notification content could be:
The trigger is the condition for delivering the local iOS notification. There are 3 types of trigger that can be used. A UNCalendarNotification, used to delivery the notification on a specified date and time, a UNTimeIntervalNotificationTrigger used to schedule the notification after a specific number of seconds, a UNLocationNotificationTrigger used to delivery a notification when the device enters or leaves a specified geographic region.
All notification triggers can be made repeatable, in which case the notification trigger will be rescheduled again once it has been delivered. Examples of the different types of trigger include:
The request is created from the content and the trigger and will then be passed to the notification centre for delivery at the appropriate time.
The request also takes an identifier string which can be used to uniquely identify the specific notification.
This can be useful for removing a specific scheduled notification or updating a notification with new details. If a new notification is required each time, the identifier can be set with a generated UUID string. Here is how you set the notification request:
We want to set up iOS local notifications that repeat on a certain date or day of the week with a weekly, monthly or quarterly period.
For this use case the UNCalendarNotification trigger best suits our needs as the `dateMatching` initializer takes a DateComponents object, allowing us to specify different units of date/time such as day of the month or day of the week.
To set a repeating notification every Monday morning would require a trigger like this:
To schedule local notifications on iOS with a recurring trigger on the 5th day of each month we can use:
To set up quarterly reminders required a slightly different use of the UNCalendarNotificationTrigger, as there is no specific quarterly DateComponents value.
We want to allow the user to select a quarterly period starting on the first day of the first, second or third month within a quarter. For example, if they want a quarterly reminder on the 1st month of the quarter they'll get a reminder on the 1st of January, April, July and October. The 2nd month of the quarter would be February, May, August and November. And the 3rd month of the quarter would be March, June, September and December.
As we can't create a quarterly DateComponents object we can instead create 4 separate repeating triggers on the 1st day of a specific month and as they are repeating, each one will repeat once a year on the 1st of the specified month.
Now we have all the required components to schedule a notification for a specified day or date, we can tie in our generic UIPickerViews to pick the correct values to use for our DateComponents.
Looking back at the previous block post, all we need to do is assign these DateComponents to each of the FrequencyOption enums and their associated type enums (WeekOption, MonthOption and QuarterOption), bearing in mind that the QuarterOption needs to return 4 DateComponents.
We can add a dateComponents variable to each of the enums which will return the set of DateComponents for the specific enum case. The top level FrequencyOption enum will return its associated types dateComponents.
In order to create the DateComponent for each case we can make the enum store a raw Int value that will be used to initialise the DateComponent. The resulting enums will look like this:
With these updated enums, the UIPickerViews created previously will now contain the DateComponents for every combination of FrequencyOption and associated value options. In the UIPickerView delegate for the associated value enum, we can trigger the creation of a scheduled notification:
There are plenty of extensions to this work. Further frequency options could be added such as a yearly or 6 monthly option. All you would need to do is add a new case to the FrequencyOption and create a new associated enum type for the new option with the required set of rawValues and DateComponents.
Even though the notifications are scheduled (so will persist on app close) when the app reopens we may want to display the previously selected option so they can change the notifications to a different period.
We would then need to persist the selection using something like UserDefaults. To do this we just need to make the enums conform to the Codable protocol so we can encode the selection using a JSONEncoder.
For more articles like this one, check out the Brightec blog. We share hundreds of articles on topics from company culture to coding hacks like this one. Have a browse, share your thoughts, and reach out on social media. We’d love to connect with you!
Search over 400 blog posts from our team
Subscribe to our monthly digest of blogs to stay in the loop and come with us on our journey to make things better!