Force Realm notification block to run before proceeding - ios

The background for this question is that I have an app in which all the tableViews are updated automatically using fine grained Realm notifications. At some point I fetch data from a server to populate a table. In the completion block of the server call, I add the newly fetched object into Realm, triggering a notification that updates the table.
The problem I'm having is that I want to start an animation that uses the newly inserted table cell immediately after adding the object to Realm. Is there a way to force the notification block to run before I proceed to the next line? Here's little pseudo code to try to clarify
Network.getDataFromServer() { json in
let realmObject = Object(json)
realm.write({
realm.add(realmObject)
})
// Realm notification block needs to complete before getting here
runAnimation()
}
Has anybody encountered a similar problem? I really like using fine grained notifications to manage table views because it's so clean, so I'd really like to find a way to handle scenarios like this one.

The right way to do this in a fully reactive application would be to perform the animation based on the notification coming in. This way, no matter how an object is being added (getDataFromServer, a bg thread, or even a different process), your app would react the same way.
This leads to simpler code while being more robust.

Related

What problem viewContext.setQueryGenerationFrom is trying to solve in CoreData project which involves transaction history?

I have came across 2 demo CoreData projects, which involves transaction history.
Both are using
viewContext.setQueryGenerationFrom(.current)
when they initialize their CoreData stack.
FireballWatch demo from raywenderlich
The demo is picked from https://www.raywenderlich.com/14958063-modern-efficient-core-data
The author is trying to demonstrate, how to make use of transaction history, to update UI correctly after batch insertion.
However, it isn't clear on what problem viewContext.setQueryGenerationFrom(.current) is trying to solve.
Code : https://github.com/yccheok/FireballWatch_Materials/blob/main/final/FireballWatch/Model/Persistence.swift#L100
Brief explanation of the article https://www.raywenderlich.com/14958063-modern-efficient-core-data doesn't tell much about the idea behind setQueryGenerationFrom.
You are pinning the view context to the most recent transaction in the
persistent store with the call to setQueryGenerationFrom(_:). However,
because setting query generation is only compatible with an SQLite
store, you do so only if inMemory is false.
Synchronizing a Local Store to the Cloud from Apple
The demo is picked from https://developer.apple.com/documentation/coredata/synchronizing_a_local_store_to_the_cloud
It is trying to demonstrate, how to use transaction history, to prevent data duplication after syncing with CloudKit.
However, it is still not clear on what problem viewContext.setQueryGenerationFrom(.current) is trying to solve.
Code: https://github.com/yccheok/SynchronizingALocalStoreToTheCloud/blob/main/CoreDataCloudKitDemo/DataProvider/CoreDataStack.swift#L89
Not much explanation is given behind the idea on setQueryGenerationFrom.
Experiment
No matter whether I have included viewContext.setQueryGenerationFrom(.current), or excluded viewContext.setQueryGenerationFrom(.current) in my CoreData stack, I am having the same observation in both situations.
Able to observe UI update immediately, after I save a new NSManagedObject, with context.save called.
Able to observe UI update immediately, after I edit an existing NSManagedObject, with context.save called.
Able to observe UI update immediately, after I perform batch NSBatchUpdateRequest operation, with mergeChanges called.
Able to observe UI update immediately, after I perform batch NSBatchDeleteRequest operation, with mergeChanges called.
There are some good graphical explanation on what is doing by setQueryGenerationFrom
https://cocoacasts.com/what-are-core-data-query-generations
However, I fail to relate it to, what kind of real problem setQueryGenerationFrom is trying to solve.
Does anyone know, what problem viewContext.setQueryGenerationFrom is trying to solve in CoreData project which involves transaction history? Would be appreciate, if there is a solid demo code example, to show what kind of problem is solved by setQueryGenerationFrom. Thank you.
It just pins some snapshot of context, so all your following queries work with exactly that snapshot, independently of what's happened after pin-moment. It's like detached checkout from GitHub - everyone goes ahead but you work with out sandbox.
This is guaranty of consistency which could be needed for some sequence of requests between which no changes should happen.
To pin we use viewContext.setQueryGenerationFrom(.current)
To unpin and continue with kind-of-HEAD we use viewContext.setQueryGenerationFrom(nil)
Additional description is in Apple's article
Taking the demo project CoreDataCloudKitDemo, it is to support the case where device1 is editing a post, and device2 deletes it. You can take look for this piece of code:
// The selected post was changed, and the user isn’t editing it.
// Show an alert, and go back to the main view to reload everything after the user taps reload.
let alert = UIAlertController(title: "Core Data CloudKit Alert",
message: "This post has been deleted by a peer!",
preferredStyle: .alert)
With the magic of query generation, we will be able to immediately pop up this alert on the device1 which is editing the post, after device2 device deletes it.
On the main listing view, there are no issues, as the item will probably just be animated out of the list. The issue is for the details view, what is going to be shown, and what happens if the user edits the value the details view.
In samples codes, this is usually following
container.viewContext.automaticallyMergesChangesFromParent = true
As in the details view, usually we will be holding on to an object, and once it is deleted, the object itself should become invalid, and accessing it or the attributes will cause unexpected behaviours.

Retrieve data/snapshot after manually remove children in Firebase

I have a function that uses .observeSingleEventOfType with .Value to retrieve data from a subtree from Firebase. The issue I'm facing right now is that, every single time I manually remove children/data in Firebase to test how this function behaves, it always loads the old data the first time when it gets called after deletion. After the first time, it then loads the correct data.
I have tried to use .ChildAdded and .observeEventType, but the behavior didn't change. I have Firebase.defaultConfig().persistenceEnabled set to true now, and I am guessing the problem is that snapshot reads data from cache if it's available, otherwise checks Firebase database.
Any one experiences this kind of issues before?
Any help would be highly appreciated.
UPDATE:
I have tested with and without persistence enabled, it turns out that I was correct, when Firebase.defaultConfig().persistenceEnabled caches all data in the past to memory, and the observe functions will try to load from memory first then go to Firebase.
When I set Firebase.defaultConfig().persistenceEnabled = false The problem went away. However, I would like to have my app work offline as well which mean I do need to set Firebase.defaultConfig().persistenceEnabled = true Is there a way to have all observe functions cache data except this specific one?
SOLUTION:
The problem is fixed now, the issue was that I didn't remove observers when the view controller was dismissed. So every time I enter the view again, another observer gets called and thus I always receive more than one call backs.

Using Parse findObjectInBackground() to set up a View in iOS

I'm stuck between two ways of developing my application and am not sure which is best. I was hoping that somebody with a bit more experience or more understanding of Parse could help me.
I am building an iOS app with Swift and using Parse for my back-end. I really enjoy Parse and it's going well.
My question: Say I'm loading a new view. The view is driven by a Parse object, meaning I am setting up Labels, tables, buttons, etc. with data from the object. I load the object in the page load. In this scenario, should I be using the findObjectInBackgroundWithBlock() method? Or should I just be retrieving it, and not moving forward until I do?
Should I just be doing things in the background when the results do not drive the immediate next steps in my code? I am hoping this makes sense. I am running into an issue where if I find an object in the background, then I can't set a label on my view with data from that object until it is found and I have to set it inside the block.
Doesn't this kind of defeat the purpose of finding the data in the background?
The purpose of find data in background is not to block the thread. As I understood you, you have to wait for parse to finish getting all the informations, because you have to create your interface with these informations.
So what I would recommend is that you let the user wait, until the interface is ready. For example with a wait-screen or something like that. Or you block some elements which take some time to load. For example a large tableview takes quite some time to load from parse. Especially if your internetconnection isn't that good.
So you should use findObjectInBackgroundWithBlock whenever possible but only allow the user to access the view, after you've loaded all necessary data to create your view.
What you also could do is do an initial access to parse. So that you set everything up at app-start. That way, you don't have to bother the user later and the user has to wait only one time at the start of your application(or If he wants to reload the tableview. for example)

MagicalRecord UIApplicationDidEnterBackground

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.

When to refresh data in iOS

I'm not sure this question is strictly limited to iOS, as it's more of a general application-design question on data integrity. But at the moment, I'm getting into iOS and have hit a "best practice" wall.
If we use the Twitter app as an example. We have one tab for our timeline and one tab for our profile. So (to keep things very simple) each one is a View Controller, backed by an object (model). I tweet on the timeline VC, then I head on over to my profile tab. Both viewDidLoad methods have already ran, so the data that was loaded to draw the UI is currently stale. The "count" of my tweets is now out of date. In the iOS world, what is the best methods/approaches to keeping the VC model data synced with the backend?
Is it on a time interval? Or network requests in the viewWillAppear method? Is it event driven, ie. when I tweet in one VC, and it's been saved in the backend web service, I notify any VCs that care that there's a new tweet
I'm not 100% sure this question will have an "answer" in the SO sense, but I'm just trying to understand what's the done thing in the iOS world (as someone who comes from the web development world).
Here's a loose sketch of some things our team has done on a networking application that might give you insight for your own architecture.
At the level of the VC (in viewWillAppear) we typically have multiple NSNotificationCenter observers that will call whatever update methods you need to run after a network update call.
Firing off these notifications is some network listener that lives on a background thread. It's job is to wait for responses from the backend server (typically JSON blobs) that contain updates to the data model. I believe ours has a time interval that will periodically phone home and check to see if we have new things to update.
Note you will necessarily have to devise an asynchronous solution for network calls as the passing/receiving of data packs can be unreliable, and take time, and thus should be computed in the background. You'll also need a way to handle data loss and other errors between server and device. And of course in order to see UI updates, you'll need to switch back to the main thread when updating the VC.
Assuming a some change of state (i.e. new message), then it makes the call to get the new data, which then fires off an NSNotification (with a new payload of info), that goes to the observer on the VC.
As you mentioned with viewWillAppear, UIViewControllers are a core building block of iOS apps. They have a lifecycle to follow to help with things like this scenario.
You have many options, but the best practices would to make calls on the viewWillAppear method and then reload your table views, collection views, etc.
Another thing you can add is push notifications on data change. You can now send a push notification with the "content-available" option that is silent and sent to your app when data changes on the backend. Then your app can refresh data only when needed.
I would stay away from timers. They will keep making network request and keep the radio from going into a battery saving idle mode.

Resources