How To Cancel Firebase Query in Swift Xcode - swift

How would you cancel a firebase query? For instance, I have two functions. In functionOne I retrieve data from Firebase Firestore. In functionTwo, I'd like to be able to cancel the retrieval process if the user hits "Cancel."
In other words, I don't want the retrieval process going on in the background still when the user cancels. I want it terminated. How can I do this?
Thanks!
I couldn't find anything on the internet about this so far.

It sounds like you have a large data set - in those cases, loading it all in at one time can overwhelm the device and cause your app to crash.
The solution is to use pagination to control the amount of data that's loaded.
While that's the main purpose of paginating your data, it also very useful when you want to give control the user and the ability to 'cancel' a query.
Simply put, if your dataset is 100,000 documents, use pagination to load in 1000 at a time and in between incrementing the pagination cursor, check to see if the user has clicked cancel.
That will be seamless to the user and will cancel when they click cancel.
This technique also enables you to add a loading bar or other indicator to the UI showing how much data has loaded.

There is no way to cancel a Firestore query once it's been started. As in: once the initial query has been sent to the server, there's no way to stop the server from executing it.
But you can stop receiving further updates by detaching any listeners from the queries.

Related

How do you speed up frontend response to user actions that require backend actions?

This question isn't specifically for flutter, but it's what I'm learning at the moment, so I'm tagging it as such.
I'm writing a flutter app where the user can "favourite" a note, which changes the state of that note's icon. I'm using firebase as backend.
The way I've implemented it is to update the state of the icon whenever the note object gets updated, but that of course takes time between the button press and the update.
This got me thinking about how do apps eliminate time between user action and feedback, when there's usually supposed to be time needed for the request to be sent to the backend, an update coming back to the app, etc?
For example: When a user upvotes a post on reddit, they can see the upvote button change state immediately, and the post's upvote counter updates accordingly, without any delay.
Do apps cache these user actions and have some way of mixing using cached information and actual backend(live) data, so that the user gets this nice immediate feedback?
Use Optimistic UI pattern. Optimistic UI immediately switches to the final state while the real operation is still in-progress. If the operation fails, rollback to the previous state and possible show error. Details how to implement Optimistic UI depends on the use case.

Delay App Progression Until Firebase Data Retrieval Is Finished

In my app, I store data on the Firebase database (Firestore AND Storage) in the form of "Files" (what the user sees). When the user goes to their "Files" tab and selects a certain file (example: "Smith vs Wesson"), the app downloads data on the server (from BOTH Firestore and Storage) related to that file. Here's my problem: the app moves forward before the data has even finished returning and processing (sorted/stored into variables). I don't want the app to progress and take the user to the next screen until this is totally complete. The next three screens show the data retrieved from the server, so if it's moving forward before the data has even retrieved and sorted... well... you see the problem with that.
I tried using something like DispatchQueque.main.asyncAfter to add a three second delay, but the problem with this is that if the user's internet connection is poor, it may take longer than three seconds to retrieve the data. Likewise, if their internet connection is booming, it may take only a second to retrieve the data, but they're still stuck waiting on an unnecessary three-second delay. I only want the delay to last as long as it takes for the retrieval/sorting/storing function to complete its tasks... no matter how short or long.
I'm still learning and am mostly self-taught, so forgive my ignorance. From what I understand from the reading I've been doing, tasks are based off of "threads." The main thread is what the user sees, while there are threads that tasks can be done in the background to keep the user from experiencing longer wait times, etc (such as data retrieval from a server). I know typically you don't want to do tasks on the main thread, but in this case where I don't want the user to be able to progress, I need to find a way to pause the main thread until the other thread has completed the data retrieval and sorting/storing process.
I stumbled across something called "CountDownLatch." I read about it and kind of understand the concept of it... but not the code at all, to be honest. I don't know if CountDownLatch is the correct method to use here or not, but if it is, could someone please show me how I could use either CountDownLatch, or some other delay, to pause the progression of the app until the data is retrieved, sorted, and stored into the variables?
My data retrieval/sorting/storing function is called "getAndAppendClaimData." I handle all of those steps in this function, and it works perfectly. Like I said, I just need to provide some delay until it's finished, so that the code underneath this function isn't executed thereby segueing to the next screen.
So something kinda like this:
while getAndAppendClaimData is still processing {
showLoadingAnimation
}
once getAndAppendClaimData has finished **ALL** of its tasks {
performSegue to next screen
}
NOTE: I DON'T use listeners in my app because I don't need to update the user's screen in realtime... like with a messaging app or something. I just use the .getDocuments and documents.forEach functionalities for my data retrieval.
Please explain your answers or provide links to content explanations. You remember how it was when you were still learning..
Also, before some of you call this post a duplicate.. the other threads are outdated and most of them deal with apps that have listeners for realtime updates – which is different from my circumstance. Another thing, I'm doing a lot of research and learning... so please don't drop the whole "go do your research" bomb. Sometimes you need help tailoring things to your specific situation.
Thanks, I really appreciate the help!
Okay so after more research, I found that one way to keep your app from progressing while server data is downloading and sorting is with DispatchGroup.
First of all, create a DispatchGroup variable:
let dispatchGroup = DispatchGroup()
Then you can "enter" the group at the beginning of the call/function and "leave" the group at the end, once everything has finished processing (such as in completion in a Firebase call). If you're utilizing a loop to sort your data, then make sure to enter dispatchGroup
dispatchGroup.enter()
every time you enter the loop and leave dispatchGroup
dispatchGroup.leave()
at the end of each loop iteration. Once you're finished entering and leaving dispatchGroup for good, then call:
dispatchGroup.notify(queue: .main) {
// Here write whatever you want to do after it's finished retrieving and processing the data...
// Such as performing a segue
}
You would call this .notify outside of your loop, of course.
In my situation, I had a two loops: one to gather/store server data and one to sort it. I didn't want it to start trying to sort until it had finished gathering/sorting, so I executed the second loop inside dispatchGroup.notify, then performed my segue after the second loop finished.
Watch these three tutorials, they helped me out big time!
DispatchQueues
DispatchGroups
Semaphore vs DispatchGroup

Why my form go to the top of my screen when my UI freeze?

I have a little issue with a form in a delphy XE2 application:
It's an old issue on this application and i have begin to work on it just since a little time.
When the user choose to launch the process with a button's event, my application launch a connexion with an OPCServer , an SQLServer and construct the form for a good following of data take on the tow servers.
The construction of my form involves a blockage of the interface (for approximately 15 sec) because of lot's of data which are necessary for make it.
When it freeze, if the user want drag the form, she go far away, and usually with the TMainMenu which go out of the screen. After that, it's impossible to use the application because we can't drag and we need to close and re-open.
In the old version, the form be already construct before the connexion. So the modification for a dynamic form isn't in link with this issue.
Life of my event :
-Open connexion with OPC Server
-Open SQL Connexion
-Send SQL Command Text
-FieldByName('') for update my UI (Button.Caption// TPage.TStaticText.Caption // TPage.Label1.Caption)
-FieldByName('') for update an array of record
-Close SQL Connexion
-Open SQL Connexion
-Send SQL CommandText
-FieldByName('') for update an other array of record
-Panel.Visible(false)
-TPage.Panel.Show;
-TPage.Panel.BringToFront;
So I haven't MainForm modification can change its position.
I'm a young developer, so I don't know why it moving and what I can make for repair that...
If you want a part of code, ask me what and i edit this, it's very long and i don't want spam answer.
Thank's for read.
The core of your problem is that you have a lengthy process (form construction) which completely blocks the main thread so your application isn't able to process normal Windows messages at the same time. That is why when you move your application it doesn't properly update its interface.
Now based on your description you already have this form construction process split into multiple steps so you could call Application.ProcessMessages between them.
This will force your application to update its UI part.
But beware calling Application.ProcessMessages often could hurt your application performance quite a bit. Why? It is usually a lengthy process because it forces your application to process all the messages that are in its queue.
Normally not all of these messages get processed as soon as they arrive. Windows groups them in the message queue by their priority list, making sure that high priority messages like WM_PAINT are processed as soon as possible while some other low priority messages like demand for application to respond to OS so that OS can see if the application is still working are mostly processed when application is idle or when they are in queue for certain amount of time.
So that is why Application.ProcessMessages can be so slow as it forces your application to process all messages regardless of their priority.
Also bear in mind that using Application.ProcessMessages can in certain scenarios actually become a bit dangerous.
Let me give you an example:
Lets say that clicking on a button starts a lengthy job which can take some time to finish. Now in order to allow your form to be updated you call Application.ProcessMessages in certain intervals. So far it is all good. But what happens if user clicks on that button again?
Since you are calling Application.ProcessMessages which forces your application to process all the messages and since clicking on button creates a MouseClick message which then fires buttons OnClick event which then executes the OnClick method that has been assigned to buttons OnClick event in the end this will cause the same method that was executed on first button click to be executed again.
So now you have this method partially done from first button click and same method executing again for second mouse click. Now the method that was executed from the second click will finish first and then the method that was started from first button click but was interrupted with Application.ProcessMessages handling the second button click will continue its execution to the end.
This all can lead to strange bugs which are hard to track, because you as a programmer normally don't predict that your end user might have clicked the button twice.
So to avoid this I strongly recommend you implement some safeguard mechanisms to prevent such scenarios by temporarily disabling a button for instance.
But the best solution is always to show your user that your application is working which in most cases will dissuade them from clicking the button again, but unfortunately not always.
You should also take a good care when dynamically constructing a form to enable the controls only after all of the controls have been successfully constructed. Failing to do so the user might click on one of your controls and that control could attempt to access some other control which hasn't yet been created at the time. The result hard to track bug which causes Access Violation.
You might also consider showing a splash screen at start instead of half built form. Why?
For once it is much nicer to see and it tells your users to wait a bit. And for second having main form hidden until it is fully created makes sure that user won't be doing any clicks on it prematurely.

How to stop runaway processes

So I'm working on this application that requests and retrieves webservice content for iPhone. The problem I am running into is this: When I initially request data, it is spawned off as an independent thread so that the application does not become unresponsive due to the network being slow. What this means is that if the user navigates away from the current page before this data finishes downloading, unexpected things can happen.
I have managed to narrow down the problem cases to one relatively simple one: I have some nested tables, so if a user goes down into the "Messages" table, which can sometimes take a little while to download, then back out immediately, and select a different set of messages to view, the previous set of messages ends up loading, because it was still in the queue.
Here are things I have tried:
1) I tried cancelling the operations, but this is futile, because since I only allow one operation in the queue at the time, it triggers immediately
2) I tried validating that the recipient of the data is the same, but this doesn't work because the actual table object is the between the two selections, it just needs a different data set.
Anyone have any general programming suggestions on how to solve this tricky threading problem?
On an iPhone specific note: if I could just stop the user from being able to back out of the messages table, I wouldn't have this problem, because they would basically be locked into that view until the data has finished loading.
Thanks!
This post has some design advice relating to iOS networking and threading. The basic gist of it is "Don't use explicit threading", and I couldn't agree more. NSURLConnection has great built-in functionality for asynchronously loading data from a URL while managing all of the threading for you. They can also be cancelled easily at will.
If you were to use the NSURLConnection paradigm, you can simply cancel any pending request when you back out of the requesting view controller.

Asynchronous data loading in Entity-Framework?

Did anyone hear about asynchronous executing of an EF query?
I want my items control to be filled right when the form loads and the user should be able to view the list while the rest of the items are still being loaded.
Maybe by auto-splitting the execution in bulks of items (i.e. few queries for each execution) all in same connection.
I posted a feature suggestion to Microsoft, please share them with your ideas as well.
Not wanting to sound like a commercial, but I noticed that the latest DevExpress grid gives features like this in their WPF grid. Essentially you want to load visible-count items first, then load the rest in a background thread so your UI isn't freezing up. The background thread should probably load another page at a time and make them available to the UI thread.
It's something you would want to think about carefully and make sure you get it right, or simply buy a control that does the hard work for you.
I take from your link that this is a web app. Is that correct?
A Query must complete and return data before rendering can begin. An EF feature will not help you here. Rather. look at breaking up your process into several processes that can be done at once.
Keep in mind that ASP.NET cannot return a response to a browser if it is not done rendering the HTML.
Let me assume you are executing a single query, getting the results back and displaying them to a page.
Best option: Page your results. if you Have 4000 records, show the first 50. If you show 200+ records to a user, They cannot digest that much information.
If that does not fit your needs, look at firing one query for 50 results. Make an Ajax call to the the remaining records and build the UI from there, in (reasonably sized) chunks.