iOS: EKEventStoreChangedNotification. When is it sent? - ios

I've got an app that shows calendar events. I want it to update whenever there's a change to the user's calendar in iCloud.
The docs claim EKEventStoreChangedNotification is sent when an event is added/removed/modified. And I have sometimes found that to be the case. But other times, no notification is sent at all. Every three minutes I call [EKEventStore refreshSourcesIfNecessary], but even that won't pick up the change. The only way I can reliably get a change detected in my app is by switching to the Calendar app, waiting for the event change to appear there (normally within a few seconds), then going back to my app…and there it is.
One more thing: I have "Push" notifications turned on my for my iCloud calendars.
Any idea what is going on here? Why is it inconsistent? And how can I make it consistent?
Thanks!

Not sure it helps, but I also hit this issue (just assuming I could rely on the EKEventStoreChangedNotification)... With the approach that you took (calling [EKEventStore refreshSourcesIfNecessary] tho, I do get consistent results, where moments after calling that method, I then receive the notification of changes. Seems to work all the time.

Related

Can IOS app do things even when it is not working at all (Killed/Non-running state)

I Did lots of BG tasks in the past, But Trying to get data when app is killed (Even when user is giving Always permission) seems not to work.
I wonder if there is a solution for that.
To make things clear, I am not talking at the moment when app change from Active or Background even to suspended mode. I'm talking about if the user is using the app and set permissions but then kills the app and after that i need every hour to get data from the user and send data to them.
Is there a way to do that?
Can a Today widget help me with that? Does a Today widget "lives" all the time and i can get that from it 24/7?
Whet is working is CLLocation manager. This is working even when the app is killed. But only when the user is changing a location.
I need that to work when the user is in the same place also.
Non of the other methods work. Not BGTask (I need every hour on the hour and not when apple decide to do things), Nor Silent Push Notification for some reason (Regular ones work, but i Don't want to bother the user with a push every hour just for getting and sending data).
Sorry there is no code to show as this is a very general question. But i think that is very important one to many people and can't find an answer for that.

Schedule UILocalNotification based on changes to Core Data

I'm making a simple app with a Today Widget extension that logs events.
The user can tap a button in the app or the related Today Widget to log an event. These events are saved with Core Data any time the button is pressed either place.
Whenever a new event is logged in the app, I run a function called updateLocalNotificationsFromCoreData(). It handles the setup of UILocalNotifications based on the most recent event in Core Data after clearing the appropriate existing notifications.
However, when a new event is logged from the Today Widget, I can't use this function because I need to register the Local Notification with UIApplication.sharedApplication().scheduleLocalNotification(), and UIApplication is not available in the Today Widget extension.
I realize I'll probably need do something unconventional or hacky to get this working, so I'm trying to evaluate possible approaches and come up with a relatively robust solution.
Basically, I want to find a way I can call my
updateLocalNotificationsFromCoreData() function right away any time a new event is logged.
If I can't do it every time an event is logged, an alternative would be to trigger the updateLocalNotificationsFromCoreData() function periodically (somewhat frequently) another way. Here are some solutions I was thinking about using, but I don't like any of them:
Do it in AppDelegate when the app is launched (or another state change)
One approach I'm thinking about is running my updateLocalNotificationsFromCoreData()function in AppDelegate somewhere, like didFinishLaunchingWithOptions.
The downside is that it would require the user to open the app periodically. If the user didn't open it much the notification behavior would be inconsistent. I'd prefer a solution where a user could interact with only the Today Widget and reliably get Local Notifications without ever opening the app.
Sync the events to a server and use Push Notifications
I've thought about syncing the data in Core Data to a server, then setting up Push Notifications to the user's phone based on that.
I don't like this, because I want the user to still be able to get notifications without an Internet connection. It also introduces a lot of extra overhead of syncing the data with a server.
Ping a server, and send a content-available Push Notification
When someone logs an event with the widget, I could ping a server. That server could send back a silent content-available push notification to trigger the app to run updateLocalNotificationsFromCoreData() in the background.
I found a similar question (Scheduling local notification from within a Today extension) where one answer proposes a similar solution. Unlike the previous solution, an Internet connection is not needed to receive the notifications, but an Internet connection would be required to make sure the notifications are up to date when a new event is logged.
Background fetch
I thought about using Background Fetch to fetch something arbitrary from a server, then run the updateLocalNotificationsFromCoreData(). This would be a way to trigger the update in the background, although it seems silly to fetch data if that data isn't being used, and seems like something for which an app could be rejected. There also seems to be a risk of the system not calling the background update regularly if the user doesn't open the app much and mostly uses the Today Widget.
Use background location updates
This seems like the dumbest approach, but I thought I would mention it anyway since I thought about it. I could use one of the low accuracy background location update modes to trigger updateLocalNotificationsFromCoreData().
It would require the user to allow location in the background, which would be hard to explain. And, it would require the user to at least move around a few blocks to trigger the function, which could provide an inconsistent user experience. Also, it would increase power consumption of the app for a silly reason.
I'd really appreciate fresh ideas about how I might be able to reliably schedule local notifications when Core Data changes on a device that doesn't have an Internet connection!
Or, if that doesn't seem possible, I'd appreciated feedback on which approach seems to make the most sense.
EDIT: I came up with a new solution. It's not ideal, but I think it's better than these other approaches I was considering. When someone taps the button to log the event, I launch the full app. It's annoying because I have all the data I need at that point to give the user feedback and log the event within the Today Widget without launching the app, but by launching the app I have the opportunity to check and schedule local notifications.
Also, in iOS 9 the annoyance on the user is slightly minimized because the system-wide "back" button will appear and let the user go back to the previous app easily once my app has launched from the Today Widget.
In the future I may try a solution where one of the server-based approaches above is used when an Internet connection is available, and I would then fall back to this system of opening the app only when the network connection is not available and I need to schedule the local notifications within the app.

How to code a diet reminder in iOS?

I'm trying to code an app that reminds me to hit a certain diet goal (drink 8 glasses of water, eat two fruits, take vitamins etc)
The problem is if I code these as reminders using local notifications, I don't get to execute code. So I can't adjust the reminders every hour relative to my goal. For example don't show the reminder if I already hit the goal. Or say stop the reminder past dinner time and start again in the morning.
If I code these as NSTimer the problem is they don't run in the background.
I suppose I can move all the logic to a server and use push notification instead. But this is huge amount of work for what I would consider a very simple self reminder app.
What is the right approach?
if I code these as reminders using local notifications, I don't get to execute code
I use a pill-taking app, and it does use local notifications. The local notification does let the app execute code, if the user taps / swipes (whatever) the notification. The app then puts up a dialog where I enter what actually happened (I took the pill, I skipped it, etc.).
The app simply assumes that if the user doesn't respond and tell it what happened, then nothing happened (i.e. the user missed the pill). How does it know that? Well, as with any local notification-based timer app, the app must maintain an internal list of pending events. It strikes a pending event from the list when it knows the outcome. That way, if the app is not running and then it is running, it can look back over its list and note that there are past pending events, thus proving that the user failed to respond to a reminder.

Use of "applicationSignificantTimeChange"

May be I am asking a stupid question here.
I recently noticed an UIApplication delegate method
- (void)applicationSignificantTimeChange:(UIApplication *)application {
}
I was wondering what will be its actual use? Do we need to handle this. Can anyone explain a scenario that can happen in an iOS application and we need to do some coding here.
My App is really sensitive to system time, that is the reason I am asking this question. After seeing this API , I have a feeling that I am missing something here to handle.
I am just curious to know... :)
Thanks,
Ramesh Chandran A
Per the documentation on iOS, this method is called:
Examples of significant time changes include the arrival of midnight,
an update of the time by a carrier, and the change to daylight savings
time. The delegate can implement this method to adjust any object of
the app that displays time or is sensitive to time changes. Prior to
calling this method, the app also posts a
UIApplicationSignificantTimeChange notification to give interested
objects a chance to respond to the change. If your app is currently
suspended, this message is queued until your app returns to the
foreground, at which point it is delivered. If multiple time changes
occur, only the most recent one is delivered.
Examples of when this should be used include:
If your app has repeating scheduled events, such as a local notification that now is past, and your app should reschedule the next notification (like daily reminders).
If your app displays data in time ago that needs to be correct, even if the user sets a bad time (for example a medical app that shows your current glucose reading or similar). If a glucose monitor showed an old glucose value as the users current glucose value for instance, the user could make the wrong decision and get hurt.
How you respond to this event depends on your application. You could for instance, read UTC from a server to see if the phone's UTC is correct within some margin, and take appropriate action, such as warning the user, or updating an internal offset between actual UTC and phone UTC.
Hope that helps.
-applicationSignificantTimeChange: is roughly equivalent to the UIApplicationSignificantTimeChangeNotification notification.
I have a custom date picker control that highlights the today date. Subscribing to this notification allows it to change its highlight at midnight, or if the user messes with the time setting manually.

NSSystemClockDidChangeNotification acts weird when app wakes up

In my app I'm registering a NSSystemClockDidChangeNotification notification in AppDelegate method application:application didFinishLaunchingWithOptions:options.
Posted whenever the system clock is changed. This can be initiated by
a call to settimeofday() or the user changing values in the Date and
Time Preference panel. The notification object is null. This
notification does not contain a userInfo dictionary.
Month ago it was working fine, but these days every time I suspend my app, lock my iPhone and leave it 2 minutes to pass, when opening the app, the selector method is called, which is weird to me. I didn't change the system or time, I just let the device idle.
Can anyone help me understand this? I just want to execute some code when the user manually change the system time, just in that case (tried with UIApplicationSignificantTimeChangeNotification but that doesn't help).
Like that: Getting iOS system uptime, that doesn't pause when asleep
But remember, this solution will fail sometimes because of out-of-sync when system tries to update time from NTP server when the Internet connection is not reachable.
This answer is a bit late but this is what the apple support team replied when I ask a similar question:
Part of the question I asked:
Could it be possible for the OS posted [this notification] if the
time/timezone has not changed in the device?
The answer I got from them:
Absolutely [1]. It's common for a notification like this to be posted
redundantly. In some cases it's triggered by a state change you can't
see. For example — and I haven't tested this theory, so it's just an
example of how this sort of thing can come about — this notification
might be posted if the system's giant list of time zone info has
changed. So, the time zone state has changed, but it's not something
that affects your app.
But in other cases, a notification might be truly redundant (-: iOS
is a complex system and in some cases this complex machinery generates
redundant notifications, and there's no need to filter them out
because…
Your app should respond to such notifications be refetching the info
it cares about and updating its state based on that. If this update
is expensive, keep your own copy of the previous state, compare the
current system state to that, and only do the update if the stuff you
care about has actually changed.

Resources