iOS do scheduled operation in background or when app active - ios

I have CoreData model which I want to update at 12 AM. So it's kind of an even when the app can recognize that a new day is coming and at 12 AM change some things in data models.
Initially, the idea was:
Prepare a single function that returns updated data. So before the function returns smth I every time check for the time (NSDate interval between two dates) and then update data model (if it's a new day). But the architecture not so simple for this purpose and it will take some time to prepare for a single point where I can get updated data, also it takes some time in background to update CoreData model which also adds some expenses to this task.
Is this ok solution to use some timer which will update data at 12 AM, I don't care about consistency in this case, but I don't like a timer which is checking every single second is 12 AM already or not. Is there some push notification update or some scheduler manager in iOS which can update data for me. One more time I just want to update the data layer and I don't care about consistency in UI. If consistency matter for sure then I would like to follow initial ide with a single point of retrieving data.
So I probably need some scheduler manager for this purpose or rewrite code of how I get the data.

There is no way to execute a function at regular intervals, even when the app is backgrounded/killed by the user.
The most reliable solution for executing a function at regular intervals even when the app is backgrounded is to use push notifications scheduled for the specific time intervals (midnight each day in your case), which would wake up the app and let it update its data. However, this solution has its downsides, since you need a server to send the push notification from and the users device needs to be connected to the internet. Also, push notifications don't wake up the app in case the user manually killed it.
For your particular problem, the best solution would be to refactor your code in a way that you have a single function that can be used to retrieve data and hence this function could ensure the data is updated in case a certain time interval has passed since the last update.

You might want to look into BGProcessingTask. You won't have granular control over when you're granted CPU time but you can set the interval you'd prefer that the task execute. Ultimately, when you run and how often is up to the system.

I would recommend checking out the new BackgroundTasks Framework Apple releases for iOS 13.
https://developer.apple.com/documentation/backgroundtasks
While you are not guaranteed at specific time if you have a window (12 am - 3 am) scheduling background tasks may be sufficient for you.

Related

In iOS11, how to keep a background task running past 10 min?

My question involves keeping an app that monitors user interactions in the background, for example time spent in one or the app. The issue arises when you can not have a background process run for more than 10 min or violate Apple's sandbox restrictions. Since I am relatively new to the Apple API, and could not find a direct answer that didn't involve location services or VOIP (which are both interesting options, but my application will not be able to use either viably), I come to ask for options in which I can understand when another app opens, when it closes, when it fetches data, and when user holds phone in certain orientation (ie when people hold their phone at certain angles to read text and etc.) for certain amount of time.
The purpose of this analyzation is to predict an attention span for the user, so I need to be able to run in the background, as the user will not be using my app while it predicts attention span.
My thoughts on this are possibly accessing the system log, and somehow parse previous statements (I don't think sandbox will allow), but inevitably the iOS system will suspend my processes after some point unless I put a timer. There is also the option of having the system wake up my app via opportunistic fetching, but that won't be useful if I don't collect the data.
Keep in mind this is within IOS 11, so it is much more restrictive than previous iterations. I understand this may seem like a complex problem, but even a direction in which to head could be useful to me.
This solution might work, (not recommended since it drains the battery quicker).
Just update your current location, every 10 mins. It will reset the background thread timer.

How to run a function at a specific time everyday using ios swift3 [duplicate]

I have read this answer and I do not believe it has what I am looking for but I a am beginner and I am happy to have someone point out the answer in this link : dispatch_after - GCD in swift?
My goal: set a function to run at 9 AM in the user's time zone (or system's time zone) every single day.
I've used GCD very briefly to delay a function as follows (it works perfectly fine):
var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(10 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
let alert = UIAlertView()
alert.title = "Foo Alert"
alert.message = "foo."
alert.addButtonWithTitle("OK")
alert.show()
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
});
So I wanted to fire it daily as I've mentioned above but the first thing I am stuck on is swapping out DISPATCH_TIME_NOW for a time zone relevant value? Do I even need to consider time zones or will simply replacing DISPATCH_TIME_NOW with military 09:00 be sufficient?
Also, any advice on the overall goal, scheduling to fire function same time every day would be much appreciated.
I'm also not married to using GCD for this goal but it was the one I ran into the most doing searches.
In short, you cannot generally execute some arbitrary function at some arbitrary time unless the app is still running. The dispatch_after presumes that the app is still running at the scheduled time, which is not generally assured. The dispatch_after is great for "do something in x seconds", not "do something tomorrow at 9am".
Yes, dispatch_after can perform some task on some background thread, but that's very different concept from having the app run in the background (i.e., when the app, itself, is no longer in foreground). Please refer to App Programming Guide for iOS: Background Execution, which enumerates all of the various background mechanisms.
The key technologies for performing something when the app is not currently active include:
Using background fetch, you can opportunistically check for new data on the server (but not per your schedule, but rather at the discretion of the OS).
If your app is serving several very specific tasks (e.g. music app, VOIP, navigation app, etc.) you can register for background operation.
You can schedule a local notification to fire at particular time (though it is incumbent on the user to see the notification and tap on it in order for the app to run). For more information see the Local and Remote Notification Programming Guide.
You can register for push notifications and then your server could push a notification to clients at some time of your choosing (but that requires server-side development).
There are other background tasks that can be configured (e.g. continue network requests in background, request a few minutes to finish some finite length task even if the app is no longer active, etc.), but those seem unrelated to your question.
If you could clarify what you want the app to do at the scheduled time, we might be able to advise what is possible and what the alternatives are. But, in broad brush strokes, those are the basic options you have.
Importantly, you should use dispatch_walltime instead of dispatch_time. The difference: If you set a dispatch_time for "1000 seconds from now" it will run 1000 seconds from now (if your app is running). But dispatch_walltime will calculate which time that is on the user's clock, and will run when the user's clock reaches that time.
So if you set up dispatch_time for 9am tomorrow morning, and I set the clock on my device forwards by five minutes, then dispatch_time will run when my clock displays 9:05am. dispatch_walltime will run at 9:00am. (You'll have to experiment what happens if I change the clock from 8:55am to 9:05am because then running when the clock shows 9:00am is obviously impossible).

Parse - How to update tableView as more data is added to the parse database?

My question is to do with the backend service parse. So far, whenever I need something, I use a PFQuery to query the database. However, I now need something a little different, and have run into a slight wall.
I have a game app that records the all time high scores. Now, I want the app to auto-update the table of high scores as more come in. For example, if the first row is currently "Jimmy: 2505" and in parse suddenly another bit of data is added where Sam gets 2604, I want Sam to be at the top of the table now.
I realise that I could just continuously send a query to Parse say every 30 seconds to check for new data, but that would be terribly inefficient, and also expensive. Is there any way that I can use that allows auto-updating without sending a query all the time? Thanks
I'd suggest using push notifications. When the user opens the app, or uses a particular view controller, subscribe them to a channel that calls for updates when the high score list is updated. In your app delegate configure how you want the push notifications to be handled. You'll have to weigh the pros and cons of api requests generated using push notifications vs a default call to update the high score list every 30 seconds as you suggested in the OP.
Push notifications should be triggered through cloud code. When a new high score is generated make a cloud call that triggers the push notifications. You can specify the kind of push notification that you'll be sending.

When should I purge waste data for my iOS app? During launch or termination?

I use CoreData and I am thinking about when I should delete waste (or expired) data.
From what I can imagine the points are as follows:
When the app launches.
When the app terminates. (in the app delegate's applicationWillTerminate:)
One is no-risk, I guess, but I don't want users to wait during the purging. (I know the watch dog exception. If the purge time is over 20 seconds, I will prepare a view controller for waiting.)
Two looks nice. The users don't see the waiting time. However, I'm not sure whether this point is suitable or not? Some people say that background process has limited time.
Either way you will most likely benefit from running your clean up on a secondary thread. You will most likely not be able to use your second option though:
Per the Apple docs in relation to applicationWillTerminate:
Your implementation of this method has approximately five seconds to
perform any tasks and return. If the method does not return before
time expires, the system may kill the process altogether.
One option you could use is cleaning up in applicationDidEnterBackground: but that also has some complications:
Your implementation of this method has approximately five seconds to
perform any tasks and return. If you need additional time to perform
any final tasks, you can request additional execution time from the
system by calling beginBackgroundTaskWithExpirationHandler:. In
practice, you should return from applicationDidEnterBackground: as
quickly as possible. If the method does not return before time runs
out your app is terminated and purged from memory.
This may be a better solution and you can dig into some recommendations via the documentation I linked to. It would probably easiest though to do it during application launch.

how to use GANTracker for long running iOS apps, including background audio

My App is typically run overnight as a baby monitor, either as foreground app, or with background audio running.
Goals:
Track total app startups ie. active user count.
Track total usage time in foreground vs background and total session time.
Track various page-views if they navigate the settings screens.
As recommended, I start the tracker in didFinishLaunchingWithOptions, and track my first ViewController as my first 'page-view'. My App might stay on this page then for the next 8 hours...
A couple of issues then appear:
When do I call stopTracker and what does it do? I'm hoping that it terminates the tracking session. But since google kindly hid their code in a static lib, I have no idea what's going on under the covers, and the .h doesn't say much. First instinct is to put stopTracker in applicationWillResignActive however, if the user decides to enable background audio my app is still running...
Next I read that a session can timeout after 30mins with no new pageviews, or at midnight. I could set a repeating timer to send the same page-view every 20mins, that should keep my session alive, at least until midnight, but then my page views are going to be much larger? unless it's smart enough to know I'm on the same page with every call. google analytics blog
[Update: each call seems to be counted as a new pageview, and numbers are thus skewed, so still an issue how to handle this]
If my timer above runs past midnight and the session has expired, I'm going to end up with a new session and double the actual active user count?
If I do call stopTracker in applicationWillResignActive, will the next call to track a page-view restart the tracker? or do I need to call startTrackerWithAccountID again?
If instead I start the tracker in applicationDidBecomeActive, I lose the session that might have been running in the background.
[update: this seems to be the best approach so far, but testing is very slow due to time lag on analytics reports, I will report back soon]
PS EasyTracker doesn't seem to handle this any better.
I got this working by using a pageview called 'Backgrounded', and when the user has selected no background functionality, then instead the app is calling stopTracker. I see multiple hits, with an average session of 20mins, but i can multiple pageview by time to see total time for goal 2. I found two solutions for goal one, events (which were not exposed in easy tracker), and also in my applicationDidBecomeActive (if it's not a restore of backgrounded app) then i track a pageview for AppStarted. I ended up wrapping the whole thing in a utility class and rolled it into a couple of my apps, so will be interesting too see the results. If anyone else tries this, you might want to think about using the custom variables too. I added my app version to this, so I can also monitor how many users are migrating to the latest app releases.

Resources