Swift - Daily Local Notification with Event - ios

In my application users will set a time. On that time I need to send them a daily notification with the count of newly created appointments. For example assume there are 3 appointments having on "01-03-2017". So on that day, at a selected time user should get a notification mentioning that "you have 3 new appointments". Newly added appointments will be saved in local realm db.
Actually what I have to do is every day user mentioned time, there should be run a code segment and check whether are there any new appointments in db. If so need to fire local notification. Even app is close this should work. I saw that in Android we can do this using alarm manager. But in swift I didn't found a way to do this.
I am not a expert in swift. So appreciate if you can give me a solution with a explanation. Thank you for your time.

You will not be able to run code at desired time, as iOS prevents from doing this.
Though, if the realm database is updated, it means the app is running at some point to add the new appointments.
When it occurs, you could have a function similar to the following to create a local notification
func createLocalNotification(atDate date: DateComponents, appointmentCount: Int) {
var content = UNMutableNotificationContent()
content.title "You have \(appointmentCount) appointment(s) today"
content.badge: appointmentCount
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: false)
let notificationRequest = UNNotificationRequest(identifier: "notification-request-\(date.day!)-\(date.month!)-\(date.year!)", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(notificationRequest)
}

Related

How to limit number of requests to a database

I have an app with a settings page where the settings of each user are stored in a MySQL database. I was wondering what is the best way to update the database for every setting the user changes while sending the minimal number of requests as I'm worried that it will crash if it sends too many( it has happened before).
I was thinking about setting a timer for ~5 seconds when the user first changes a setting, and then reset the timer to 5 seconds again if another setting is changed. Once that timer is finished it will send a request to the server to update all the settings at once. It would also constantly store the new values locally to the app, so if the user closes the app before the 5 seconds are up it will send the request once/if the app loads up again.
Is this viable/what's the best way to go about this?
You need to make some logic functions in your app, so i will try make an pseudo codes below. Hope it will give you an idea. I don`t know the MySQL details but i am trying to explain native Swift way.
First of all you should fetch data partly, I mean if you try to fetch all data at the same time your app can work very slow.. That is why we are doing pagination in the app.
As well as pagination you want to refresh the data fresh 5 seconds so i will use Timer object, which will trigger every 5 seconds the API function and catch data based on pagination. Check your below codes and implement step by step to your project. Happy Coding.
var timer: Timer?
func scheduledTimerWithTimeInterval(){
// Scheduling timer to Call the function "loadNewDataAutomatically" with the interval of 5 seconds
timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.loadNewDataAutomatically), userInfo: nil, repeats: true)
}
#objc func loadNewDataAutomatically(_ pageNumber: Int, _ pageSize: Int, onSuccess: ((Bool) -> Void)?, onError: ((Error) -> Void)?){
// Call your api here
// Send true in onSuccess in case new data exists, sending false will disable pagination
// If page number is first, reset the list
if pageNumber == 1 { self.list = [YourDataModel]() }
// else append the data to list
self.list.append(apiResponseList)
// If Api responds with error
onError?(apiError)
// Else end success with flag true if more data available
let moreDataAvailable = !apiResponseList.isEmpty
onSuccess?(moreDataAvailable)
}
Assuming that the Database (MySQL) is on a server
You can try using WorkManager for this requirement.
When the user changes their settings, save them locally (which you are already doing)
enqueue a Unique Periodic Work Request using WorkManager & set up the time at what interval should the response be sent to the server.
Minimum time interval is around 15 min. but not guaranteed at exactly 15 minutes,
the system fires it when it seems fit, also according to the Constraints that you set on your Work Request.
You can also use a OneTimeWorkRequest, if you don't need periodic, with an Initial Delay of whatever time you need.
Edit: This question was later edited and ios, swift tags were added where previously it was for android.
If anyone comes here searching for something similar for Android, this would work.

Running local notifications with hourly interval every day for specific amount of time

How can I make my app to be able to fire local notifications every day with customisable interval but only for allocated amount of time, for example: from 10:00 to 20:00pm?
Now I only implemented repeated notifications with custom interval:
func beginNotifications(_ config: UserConfig) {
let interval = config.notificationInterval
let center = UNUserNotificationCenter.current()
center.removeAllPendingNotificationRequests()
let content = UNMutableNotificationContent()
content.title = "Content title"
content.subtitle = "Content body"
content.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: true)
let request = UNNotificationRequest(identifier: "notification", content: content, trigger: trigger)
center.add(request)
}
By far I only came up with solution - to make two separate methods using Timer, which will start and stop notification function daily, and enable Background Mode for the app.
The first solution came to my mind if scheduling the local push notification N-times (how many times as you want). You just need to make the identifier unique of course.
By far I only came up with solution - to make two separate methods
using Timer, which will start and stop notification function daily,
and enable Background Mode for the app.
This isn't recommended imo, and if you push this, you might need to deal with Apple review team.

Question on how to proceed with UNUserNotificationCenter 64 limit

I am trying to make a reminder app and all my notification repeat is set to true
Example :
var dateComponents = DateComponents()
dateComponents.weekday = 1
dateComponents.hour = Int(hour)
dateComponents.minute = Int(minute)
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let requestIdentifier = "\(timeArrayToSaveInMobile[indexTime].alarmId!)Sunday"
let request = UNNotificationRequest(identifier: requestIdentifier, content: content, trigger: trigger)
I've browse around here and some people mentioned that the system keeps the soonest-firing 64 notifications.
So, if I have already reached the limit but I set another notification that will fire earlier than some of the notification in the (64 list) it should replace one of the notification right? Since it will fire earlier that some of the pre-set notification in the list.
My problem is similar to this ios 10 swift 3 add more than 64 local notifications does not keep soonest
Notifications will reset when you open the app, thus you can set/send another 64 after every time you close the application.
The system discards scheduled notifications in excess of this limit, keeping only the 64 notifications that will fire the soonest. Recurring notifications are treated as a single notification.
in your example you have set one notification for Sunday which is only count one for each Sunday.

Limiting local notifications set at the same to one

I've implemented a date picker for setting reminders which sends a local notification. During testing, I noticed I can set a reminder multiple times at the same time. I assumed the system would recognize I've already set it once at that particular time, and would not save another reminder. Surprisingly, the app sent more than once notification at the same time.
I figured I implemented this incorrectly so I decided to test the default Clock app. Again, I set two alarms at the same time, and I got two notifications concurrently:
Is this a normal behaviour for notifications? Are my assumptions wrong? Maybe this would've been okay when the user wanted to assign different messages to separate notifications. However, in my case, the app is supposed to remind users for one simple task, with a static message.
Is there a way to fix this "problem"? The way I see it, if I've already set a reminder, the app should still show that a new reminder has been saved, but not actually save the new one.
This is the normal and intended behaviour. Two notifications might have the same time but completely different data, so they are not restricted to one per unit time.
I would set the unique identifier of the notification and keep track of them in an array.
Here is an example:
let center = UNUserNotificationCenter.current()
// Setup content
let content = UNMutableNotificationContent()
content.title = "Notificaion title"
content.body = "Yoir text here"
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "YouCanHaveDifferentCategories"
content.userInfo = ["myKey": "myValue"]
// Setup trigger time
var calendar = Calendar.current
let now = Date()
let date = calendar.date(byAdding: .second, value: 10, to: now)
let trigger = UNCalendarNotificationTrigger(dateMatching: date, repeats: false)
// Create request
// Set any unique ID here. I use the UUID tools. This value is used by notificaion center, but I alsp store it in an array property of the relevant object in my data model, so the notification can be removed if the user deletes that object.
let uniqueID = UUID().uuidString
let request = UNNotificationRequest(identifier: uniqueID, content: content, trigger: trigger)
// Add the notification request
center.add(request)
You can then selectively delete notifications with these methods, as long as you have a record in an array or your data model of the identifiers. You can pass an array to delete multiple at once.
center.removePendingNotificationRequests(withIdentifiers: "UniqueID")
center.removeDeliveredNotifications(withIdentifiers: "UniqueID")

Creating multiple local notifications at once fails

I'm working with local notification on iOS, but I'm having some problems when iOS tries to create the notifications. Some of them are created and some won't.
After reviewing my code a lot, I found that it was failing at the point where it was creating the local notification.
UIApplication.sharedApplication().scheduleLocalNotification(notification)
The only reason I could think of was that creating the notifications inside a loop, around 50-60 notifications, was too much for iOS to process. I'm doing it this way because all the notifications have a different time and different day, and belong to different things.
This is my block to create the local notifications:
let createdUid = self.generateNotificationUUID()
// create a corresponding local notification
let notification = UILocalNotification()
/* Time and timezone settings */
notification.fireDate = self.buildTime()
notification.repeatInterval = NSCalendarUnit.WeekOfYear
notification.timeZone = NSTimeZone.systemTimeZone()
/* Information settings */
notification.alertBody = "Sector \(notificationData["sector"]!): located at \(notificationData["name"]!) closes in 15 min."
notification.alertAction = "Open"
/* Badge settings */
notification.applicationIconBadgeNumber = UIApplication.sharedApplication().applicationIconBadgeNumber + 1
notification.soundName = "ring.caf"
notification.userInfo = ["UUID": createdUid, ]
/* Schedule the notification */
UIApplication.sharedApplication().scheduleLocalNotification(notification)
And all this code is inside a loop. The same loop before calling the notification creation, dynamically builds the notificationData array.
The notification data array contains the sector, the name, and the time and day.
Time and day is used to calculate the notification fire date.
Sector and Name are used for the alert body.
And all the four values are used to generate the UID (UUID).
If I put a print and remove the UIApplication.sharedApplication()... all the data looks good and what it needs to be.
I've tried, to solve the problem, using
dispatch_async(dispatch_get_main_queue()) {...}
and
dispatch_sync(dispatch_get_main_queue()) {...}
But with async I received the same result that I had without it, and using sync my screen freezes.
I kind of lost with this, I'm sure that my issues are because iOS doesn't process in time all the notification creation, but I dunno how to fix it.
I hope someone can help me, I'm using XCode 7.3.1 and Swift 2.2
From the documentation: https://developer.apple.com/library/ios/documentation/iPhone/Reference/UILocalNotification_Class/
An app can have only a limited number of scheduled notifications; the
system keeps the soonest-firing 64 notifications (with automatically
rescheduled notifications counting as a single notification) and
discards the rest.

Resources