Pushing data to all devices when database changes with Realm Swift - ios

I know that Realm offers two way syncing and can trigger server-side events when data changes.
I am making a sort of messaging app, my question is how would I implement it so that when someone writes a message (which will update the DB), how does this message immediately display on other devices?

All you have to do is to open the same Realm on all devices, then they will all see the changes instantly as they happen (as long as they are connected of course :-)).
Check out the tutorial, it shows the data being realtime synced between both an iOS app, a Mac app and the Realm Browser: https://realm.io/docs/tutorials/realmtasks/

I'm one of the developers working on Realm Tasks, incorporating the latest features of the Realm Mobile Platform into it. :)
Making a chat app has become significantly easier with the release of client Realm sharing in Realm 2.3.
To make a chat app, the logic flow would be something like this:
A user starts a new chat room. This would be represented in RMP as a single, private Realm file belonging to that user.
The user can then invite other users access to that chat room via the sharing mechanism.
Every user can then contribute messages. Each message would be a separate Realm Object written to the shared Realm.
Each time a new chat message object is written to the Realm, it would be synchronized with every other user in the room.
Please let me know if you need any additional clarification.

Related

When using NSPersistentCloudKitContainer: what to do if the user logs out of iCloud?

From several Apple WWDC talks on CloudKit, when using CloudKit to sync private user data across devices, when the user logs out of iCloud, the App is supposed to empty the on-device cache / local replica (I use Core Data for on-device permanence). Then when this user (or any user really) logs back into his respective iCloud account on that same device, the device is then supposed to sync back down the data from the corresponding iCloud account. Makes sense!
I was wondering how I can achieve this when I use NSPersistentCloudKitContainer (instead of writing all that CloudKit code myself). I looked at the sample code related to Apple WWDC 2019 session 202 ("Using Core Data with CloudKit"), and this code does not what I want (the sample just does not focus on the iCloud account part, that is why they do not bother to empty the cache, I think): Indeed the NSPersistentCloudKitContainer stops synching if I log out the user, but it picks up again synching when I log back in. That is actually more like the desired (and indeed also actual, which is good) behaviour by the sample App when my web connection goes offline for a while.
But if the user logs out of iCloud (I use CloudKit framework to be informed about user account logout and login status), what I would need to do is somehow:
"disconnect" the sqlite store from the NSPersistentCloudKitContainer, then
empty (or even delete) the database, and then,
when the old (or another) user logs in, initialise a new NSPersistentCloudKitContainer (that will recreate an empty database as if the App would be used for the first time ever), so communication with the respective Cloud database can proceed.
I can not just empty the database WHILE being "connected" to the NSPersistentCloudKitContainer, as it records all the deletes and as soon as the (same) user logs in again, these deletes are synched to the Cloud, which I of course do NOT want.
Is this how one does it, aka essentially follow these three steps?
And if yes, how do I do step 2? Since I must use some kind of NSPersistentContainer to talk to the database, Apple warns not to directly do file system operations but only via Core Data. So do I need to init a "standard" NSPersistentContainer (without a communication pipe to the Cloud), and then destroy the database (e.g. using e.g. the coordinator instance method destroyPersistentStore())?
Or is there another approach for achieving the same thing?
Thank you very much for any help!!

What is considered too heavy for UserDefaults?

I'm building a simple iOS app that will be the first I'll have put on Apple's App Store. At one point, the app accesses the user's contact list and lets them select any number of contacts they want to save as favorites.
For ease of building version one, I am currently using UserDefaults to save these favorites. While it has worked well in my limited testing, I know that Core Data and CloudKit are stable options for larger solutions.
For an app like mine, where I'm only using UserDefaults to save a select number of contacts as favorites, is UserDefaults an adequate solution? Or should I transition to something more robust like Core Data or CloudKit? There is no limit on the number of contacts a user could select as a favorite, so there is the edge-case possibility of a user selecting all of their contacts one by one and attempting to save them all as favorites.
If the user gets a new phone and loses all existing data due to UserDefaults being local on the device, it would not take long to get this app back to where they previously had it.
You can use CoreData to store favorite contact locally for large data as per your concern. Now when user switch device or delete app then all data will removed. So for that you can sync with cloudKit or other option is backend server. When user add any contact as favourite same time that contact will add to Core data as well as in backend server. You can sync this backend server data when user login first time in the app, then you no need to sync again. other all thing are as per requirement.

Share database [core data] between different devices, not just the user's ones

What is the best way, to share a database between different devices, that are not just the user’s ones, but for example could be his friend’s phone. That means that iCloud is not an option.
Example:
 All of my data is app-user specific, so basically:
user logs into my app, do some work
then he can log in with the same acc on his friend phone and data should be the same
Is there an any way to upload the whole user specific database to some online storage provider (like firebase,… ) and then download it on another device and initialise core data stack, when the same user logs in on a different device?
Or is it the only way to sync data with the server and than preload the database?
You could simply upload the whole database file(s) and then download it on another device. The problem though is portability. You need to ensure that both devices support the same version of the database so they are compatible. To port the same thing to another platform is again a different story but doable when not using core data.
Then there is a problem of conflicts. Imagine you forget to log out from the second device and you open it after a week and the database is accidentally synced back to the server. This will make you lose all the data you created on your "main" device.
So in general it is possible to sync the whole thing but you will have loads of issues. You should create a server that supports all entities and works through ids (so you know the object was modified and not created) and date modified to be able to resolve conflicts.
Syncing data between multiple devices is the biggest reason to use something like Firebase. That's one of its primary purposes. You would use Firebase for data storage instead of Core Data, and it would automatically handle syncing between devices. You don't write code to upload or download anything, you just read and write Firebase data and it handles the syncing. It supports user accounts, so if a user logs on on a different device, their data automatically syncs to that device. There are numerous other options besides Firebase, of course.
CloudKit also syncs between different devices, but it's linked to the current iCloud account on the phone. Since you want in-app login, it's not so good.

Using Firebase with multiple users in an iOS app

A number of iOS apps I develop are used in scenarios where the Organisation has a number of Drivers and the iPhone is shared between them. Each Driver has his own app credentials, logs in to the app, and is presented with his own set of data. The Firebase data is persisted as he is offline most of the day and I use keepSynced(true) to ensure data is up-to-date.
The problem I'm having is that once a user logs out with the Firebase method FIRAuth.auth()!.signOut() then when a different user logs in, he sees the previous users' data. I'm guessing that because the data is persisted it is not cleared from the cache. However, I am retrieving the data by the user id so this doesn't quite explain it.
What is the best pattern to permit multiple users to use the same iOS app with Firebase ?
Try creating multiple instances of FIRApp, each with a different name, using the +configureWithName:options: method. Then use the different apps in FIRAuth +authWithApp and elsewhere as needed.
I haven't actually done this and am too new to Firebase to say it's the best pattern, but it seems like it should work.
One thing to note from the docs is that, "On Android and iOS, Analytics are only logged for the default app." One solution might to keep the __FIRAPP_DEFAULT app, and then make a named app for each user type.

How do I cache Firebase data for offline usage?

I build apps that bundle up JSON data. I want to switch to Firebase as my backend, but I need to ensure I can access the data even if firebase is offline. There's no guarantee that the user will have an internet connection at the time they launch the app. The data consists of a fairly large JSON blob.
I heard that firebase does cache data on iOS for offline access, and that's great. I just need to know how to bundle the data for that first time the app is ran, so the user can use the app prior to getting to a network connection.
As it sounds like you discovered, the Firebase Obj-C client does have beta support for offline access / disk persistence. Details can be found here.
But that doesn't address your desire to "seed" the app with initial data so that it has data available before the app has ever been able to connect to Firebase. Unfortunately, there's no direct support for that.
One hacky solution you could attempt with Firebase is to just do a setValue with the data in question, in order to seed the cache. This should work but will eventually try to write that data to Firebase, when the app gets connected, so you'd probably want to have security rules to prevent the user from actually modifying that data. As I said, it'd be a hacky solution.
For now it might be best to just handle this with special logic in your app that pulls data from some other data source (hardcoded values or an embedded file or whatever) until the first time you get data from Firebase.
Sorry there's no direct support for this at the moment. We'll take a look to see if we could support this more directly in the future.

Resources