App stops responding to user input whilst task is ongoing. Any way to prevent this? - iphone

When it gets to a certain line of code in Flite, it takes about 2 minutes to get through that line, converting what's written into text-to-speech to be played back.
During this process, the app stops responding to any user input, dealing with it once it's finished with the code from Flite. Obviously this is an inconvenience. Is there any way to prevent it?

You should do any long processing in a background thread, not in the UI run loop, using something like NSOperationQueue, plus a completion callback to inform the UI when the processing is done.

Related

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

Android Async Task does not update UI when application is in background

The application I am working on downloads and parses a large xml file to populate UI elements, namely search and a spinner. This is done through an async task. If the user decides to switch out of the application during this, the information is downloaded correctly, but then when the application is resumed, the UI will not be updated.
Is this because the changes can't be made while the application is not active? What is the best way to go about checking whether the UI was not updated on resume? Or instead should I be doing something with the Async task, checking whether the UI thread is available? I'm having a hard time debugging this because it involves leaving the application which ends the debugger.
You can achieve this scenario through the broadcast receive.
Follow the step:
Solution 1:
Step 1;
Register the broadcast receiver before executing the Asyntask.
Step 2:
send Broadcast in onPostExecute method of Asyntask.
step 3:
And then you can able receive your broadcast message in your activity.
and do whatever you want.
Solution 2:
Otherwise you can use Interface Call back for this Scenario.
Hope It will help you.
It should'nt. App being in background means View objects may or may not be there. Actually the entire process may be stopped or just deleted by android.
Use a Service to truly do processing in background. When processing is complete but UI is not there, post a notification to let user know, OR, save the results and provide it to UI the next time it binds to your service and ask for same thing (a.k.a caching).
The application in background may not be live. The O.S may destroy it in case of memory constrains.
The trick is to try an alternate logic.
When the application moves from background to foreground onresume() is called ,you could try saving the data to db and update the content on the resume call.
FYI.onPause() and OnResume() is called when the application goes background and foreground respectively.

Reachability hangs application

Currently i am following thread to check wheather my internet is active or not in my application, but as it is taking time to give the response ,so this will freeze my UI.
So is there any way to implement it without freezing UI(like NSOperation).
If the internet is indeed down, it takes time. It is limitation of Apple's API. We have to live with it or put a timer to cancel the operation after 30 secs or so. But if a genuine response especially via GPRS takes more than 30 secs, you will be canceling that too if you put timer condition.
Alternatively, you could check for internet status asynchronously and display an ActivityIndicator or similar in the main thread. This means that you create a new thread which will run parallel with your main thread (in your case, the GUI that are freezing).

Send Network Message When iPhone Application is Closed

My iPhone application supports a proprietary network protocol using the CocoaAsyncSocket library. I need to be able to send a network message out when my iPhone application is closed. The code that sends the message is getting called from the app delegate, but the application shuts down before the message actually goes out. Is there a way to keep the application alive long enough for the message to go out?
Bruce
The docs from Apple don't specifically state this, but the sense I get from looking around the Web and from personal experience is that you have about 4 to 5 seconds after the user hits the Home button to shut your app before your application actually terminates. The iPhone OS is controlling this so you can't block the termination to allow your program to finish first. Basically when your time is up, your program is killed.
There may be another solution, though. First I'd confirm that your code is really taking more than 5 seconds to run. Perhaps you can have it run in response to a button tap, and time how long it runs. If it is more than 5 seconds, you probably are running into this time out issue.
You might then find a way to trigger a message to be sent from a server that is always running. You should have enough time to trigger a remote action, which in turn could then take as long as it needs to run.
Or perhaps you could save the vital information to the iPhone file system on exit, and send that message the next time someone starts the application, which should theoretically give you enough time.
Hope this helps!
I assume you're already calling it from your AppDelegate's:
- (void)applicationWillTerminate:(UIApplication *)application
But as you've discovered there's no guarantee it'll be called or will be allowed to finish. There are a few options that may or may not work depending on what you're trying to do:
If you need the server to perform some sort of cleaning operation triggered by when the client app is gone then you could try watching for TCP socket closure on the server and treating that as the triggering event. But if you explicitly need to send data back with the closure this may not work.
If the data you're sending back is not time-sensitive then you can do like most of the analytics libraries do and cache the data (along with a uuid) on the client then try to send it on app closure. If it goes through, you can clear the cache (or do it the next time the app is run). If it doesn't, it's saved and you can send out when the app is run next. On the server, you would use the uuid to avoid duplicate requests.
If the material is time-sensitive then your best bet is to implement heartbeat and send periodic updated values to the server. Then when the client app dies the server times out the heartbeat and can use the last received value as the final closing point of data.
In either case, if an explicit closure event is required by your custom protocol then you may want to reconsider using it in a real-life mobile environment where things have to be much more fluid and tolerant of failure.
As others have noted, there's no way to be absolutely certain that you'll be able to send this, but there are approaches to help.
As Ken notes, you do in practice get a few seconds between "willTerminate" and forced termination, so there generally is time to do what you need.
A problem you're almost certainly running into is with CocoaAsyncSocket. When you get the "willTerminate" message, you're on the last run loop of the main thread. So if you block the main thread, and CocoaAsyncSocket is running on the main thread, it'll never get processed. As I recall, CocoaAsyncSocket won't actually send all the data until the next event loop.
One approach, therefore, is to keep pumping the event loop yourself:
- (void)applicationWillTerminate:(UIApplication *)application
{
// ...Send your message with CocoaAsyncSocket...
while (! ...test to see if it sent...)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
I've also looked at putting this work onto a background thread and letting the main thread terminate, in theory letting us go back to Springboard while continuing to run for a few seconds. It's not immediately clear to me whether this will work properly using NSThread (which are detached). Using POSIX threads (which are joinable by default) may work, but probably circumvents any advantages of the background thread. Anyway, it's something to look at if useful. In my apps, we've used the "post next time we launch" approach, since that always works (even if you crash).

Application.DoEvents, when it's necessary and when it's not?

What is the necessity of using Application.DoEvents and when we should use it?
Application.DoEvents is usually used to make sure that events get handled periodicaly when you're performing some long-running operation on the UI thread.
A better solution is just not to do that. Perform long-running operations on separate threads, marshalling to the UI thread (either using Control.BeginInvoke/Invoke or with BackgroundWorker) when you need to update the UI.
Application.DoEvents introduces the possibility of re-entrancy, which can lead to very hard-to-understand bugs.
Windows maintains a queue to hold various events like click, resize, close, etc. While a control is responding to an event, all other events are held back in the queue. So if your application is taking unduly long to process a button-click, rest of the application would appear to freeze. Consequently it is possible that your application appears unresponsive while it is doing some heavy processing in response to an event. While you should ideally do heavy processing in an asynchronous manner to ensure that the UI doesn’t freeze, a quick and easy solution is to just call Application.DoEvents() periodically to allow pending events to be sent to your application.
For good windows application, end user doesn’t like when any form of application are freezing out while performing larger/heavyweight operation. User always wants application run smoothly and in responsive manner rather than freezing UI. But after googling i found that Application.DoEvents() is not a good practice to use in application more frequently so instead this events it’s better to use BackGround Worker Thread for performing long running task without freezing windows.
You can get better idea if you practically look it. Just copy following code and check application with and without putting Application.DoEvents().
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
For i As Integer = 0 To 1000
System.Threading.Thread.Sleep(100)
ListBox1.Items.Add(i.ToString())
Application.DoEvents()
Next
End Sub
Imho you should more less never use it, as you might end up with very unexpected behavior.
Just generated code is ok. Things like you are executing again the event handler you are currently in,because the user pressed a key twice etc etc.
If you want to refresh a control to display the current process you should explicitly call .Update on that control in instead of calling Application.DoEvents.