MagicalRecord UIApplicationDidEnterBackground - ios

I use MagicalRecord as a good library for working with Core Data. My question is how can I save data before my app will enter background. Because I try to write data via block and of course it will not work because the app will be suspended.
So how can I update or put my object in context and save it. Usually I use method that allow import all data from dictionary and save it and it works perfect while app is running.

I'm assuming you want to do this in someplace other than your AppDelegate since you have references to actual data objects. The easiest way I can think of is to listen for the UIApplicationDidEnterBackgroundNotification and perform your save operation there. What you may also need to do is use the iOS backgrounding API so that the task can complete while it's running in the background. You may also want to listen to one of the notifications fired prior to actually going into the background as well. UIApplicationWillResignActiveNotification seems as appropriate, and you may not have to deal with the backgrounding API.

Related

When to save Singleton data in Swift?

So I'm using a global singleton to manage my app's data, that I need to be persistent throughout app launches. Thus, I'm writing the singleton's data to a file, and reading them in the init method.
My questions is when to save the singleton back to the file. Right now whenever I make any change to my singleton, I also call .saveData() to save them, but this means I overwrite a file a lot more than I need to.
I'm trying to prevent any data loss due to my app's termination and I was thinking of saving my data inside applicationWillResignActive or applicationDidEnterBackground, instead of saving every time I make a change. Another idea that came to me while reading the swift iBook is to actually call saveData in my singleton's deinit {}, but I'm not sure if a destructor is suited for the job of writing everything to a file before destroying the object.
Is any of the above methods guaranteed to save my data the day I want it? (Let's assume that my app does not crash, since if it does it's understandable that some data will be lost)
What is the best time to call my saveData() method?
P.S.: In the future I'll use CoreData for saving my data instead of a file, but for now I need a my data up and running to put the rest of the app (UI, animations, networking etc) together.
I'd use a combination of applicationDidEnterBackground and applicationWillTerminate.
applicationWillTerminate - This is your 'goto' method for doing clean up/saving before the app is terminated. However, it won't trigger if the app was suspended before termination.
applicationDidEnterBackground - Because the previous method doesn't trigger if the application process is suspended first, you'll want to trigger on background as well because the application will enter background before suspension (the case where applicationWillTerminate alone would be insufficient)

When and why should you use NSUserDefaults's synchronize() method?

So I've had a look at the apple documentation on the NSUserDefaults's synchronize() method. See below for reference:
https://developer.apple.com/reference/foundation/userdefaults/1414005-synchronize
The page currently reads:
Because this method is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes.
However, what I still don't understand is when should this method be called? For example, should it be called every time the user changes the app's settings? Or should I just trust that the background api is going to handle that? And does the leaving of the view immediately after a settings change in memory result in that change being lost?
Also, when might a failure to call synchronize() result in user settings not getting changed correctly?
Furthermore, what is the cost (performance, memory or otherwise) of calling this method? I know it involves reading and writing from/to the disk but does that really take that much effort on phones?
There seems to be so much confusion about user defaults. Think of it this way. It's essentially the same as you having a global dictionary available throughout your app. If you add/edit/remove a key/value to the global dictionary, that change is immediately visible anywhere in your code. Since this dictionary is in memory, all would be lost when your app terminates if it wasn't persisted to a file. NSUserDefaults automatically persists the dictionary to a file every once in a while.
The only reason there is a synchronize method is so your app can tell NSUserDefaults to persist the dictionary "now" instead of waiting for the automatic saving that will eventually happen.
And the only reason you ever need to do that is because your app might be terminated (or crash) before the next automatic save.
In my own apps, the only place I call synchronize is in the applicationDidEnterBackground delegate method. This is to ensure the latest unsaved changes are persisted in case the app is terminated while in the background.
I think much of the confusion comes from debugging an app during development. It's not uncommon during development that you kill the app with the "stop" button in the debugger. And many times this happens before the most recent NSUserDefaults changes have been persisted. So I've developed the habit of putting my app in the background by pressing the Home button before killing the app in the debugger whenever I want to make sure the latest updates are persisted.
Given the above summary, let's review your questions:
should it be called every time the user changes the app's settings?
No. As described above, any change is automatically available immediately.
Or should I just trust that the background api is going to handle that?
Yes, trust the automatic persistence with the exception of calling synchronize when your app enters the background.
And does the leaving of the view immediately after a settings change in memory result in that change being lost?
This has no effect. Once you add/edit/delete a key/value in NSUserDefaults, the change is made.
Also, when might a failure to call synchronize() result in user settings not getting changed correctly?
The only time a change can be lost is if your app is terminated before the latest changes have been persisted. Calling synchronize when your app enters the background solves most of these issues. The only remaining possible problem is if your app crashes. Any unsaved changes that have not yet been persisted will be lost. Fix your app so it doesn't crash.
Furthermore, what is the cost (performance, memory or otherwise) of calling this method? I know it involves reading and writing from/to the disk but does that really take that much effort on phones?
The automatic persistence is done in the background and it simply writes a dictionary to a plist file. It's very fast unless you are not following recommendations. It will be slower if you are misusing NSUserDefaults to store large amounts of data.
Apple's documentation for synchronize() has been updated and now reads:
Waits for any pending asynchronous updates to the defaults database and returns; this method is unnecessary and shouldn't be used.
UPDATE
As anticipated, it has been deprecated as mentioned in Apple Doc
synchronize()
Waits for any pending asynchronous updates to the defaults database and returns; this method is unnecessary and shouldn't be used.
Original Answer
-synchronize is deprecated and will be marked with the NS_DEPRECATED macro in a future release.
-synchronize blocks the calling thread until all in-progress set operations have completed. This is no longer necessary. Replacements for previous uses of -synchronize depend on what the intent of calling synchronize was. If you synchronized…
— …before reading in order to fetch updated values: remove the synchronize call
— …after writing in order to notify another program to read: the other program can use KVO to observe the default without needing to notify
— …before exiting in a non-app (command line tool, agent, or daemon) process: call CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication)
— …for any other reason: remove the synchronize call
As far i know, synchronize is used to sync the data immediately but iOS can handle that in smart way. So you dont need to call it everytime. If you call it everytime then it will turn to performance issue.
Check apple documentation:
Official Link

Can RealmCollectionChange be used as a way of syncing data back to server?

I noticed that in Realm Swift, there is a RealmCollectionChange
https://realm.io/docs/swift/latest/#realm-notifications
It seems to contain the objects that have changed. Can I use that notification block to add code to sync the data back to a back end database?
Is the notification block running on the main queue?
For sure you can use the provided notification mechanisms to propagate changes to a server. You should make sure though, that your requests to the server doesn't cause new changes once the server responds, otherwise you can run into a situation where you would be constantly notified about new updates, as also seen in the related docs section User-Driven Updates.
The notification block is ran on the thread on which you add it. But these APIs are only available to auto-updating Realms which require a runloop. By default only the main thread has a runloop, if you don't run any additional yourself on dedicated background threads.
Be aware that synchronizing is a non-trivial problem and using these notifications alone won't give you a full solution for every challenge involved into that problem space.

How to perform Core Data operations while the app is in background

I have an iOS app enabled for "Location updates" Background Mode. I need to save part of the received CLLocation objects information with Core Data in order to send later some related information to a web service (also while the app running in background). I've made some tests of inserting and saving using the NSManagedObjectContext of the AppDelegate and in no separated thread, and it seems to work (at least running in the simulator). But I don't know if this is actually the appropiate way to do this. I've been looking for information regarding using Core Data while the app is in background state with no success.
My question is: is this safe? I mean, could my implementation cause any exception or conflicting state or loss related to Core Data and the information I want to save? Should I create a separated thread to handle this? Or what the best way to manage this scenario should be?
Thanks in advance
You are already playing the nice shot. Still my recomandations are :
Use geofancing. This will notify your app for selected change of range in locations.
I don't know why you asked to make a separate thread. Just enqueue the task in dynamic dispatch. Even if you want to make a separate thread. Fine.
Core data will definitely save while app is in background. This type of app can remain in background forever.
Use one Managed Object Context per thread. Managed object contexts are not thread safe.
As you are using location in background you can achieve saving of care data in background
First thing check if your app properly runs in background for location.
*Note : Don’t test it connecting to mac or debugging mode through cable.
Then in the below method if all goes well and application gets location.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
Add values in Core data
If you are having different viewController to save data, fire location notification and add observer to the add value in core data

Delete data when app is killed in the background.

I have an app where I am saving data but when the app is killed in the background I have to delete all the saved data.
I tried using this method:
- (void)applicationWillTerminate:(UIApplication *)application
But its not working. Can someone please suggest me how to do that?
Not sure why you need to wipe the data on terminate specifically, but here is something to consider:
Another way to handle this type of situation when apps write data that may be incomplete when they are forced to quit, is that they write out a flag when the data is known to be good.
That way, if the app exits normally, the data will be written and the flag will be written.
If the app is forced to quit, the flag will not get written by nature of the forced quit.
THEN, when the app starts it can look for the flag. If the flag isn't there, the app knows that any data is incomplete and can discard it (delete it) and start over.
Hope this helps.
applicationWillTerminate: is basically never called and you should no longer rely on it.
The app is not given any callback when it is killed so you can't do anything. You need to decide on a different approach based on the actual user requirement. This may involve encryption / not holding certain data on disk (only ever in memory) / etc...
I know, I'm super late to the party but, if you can live with data "sticking around" until the next app launch you can delete/clear data in application(_:didFinishLaunchingWithOptions).

Resources