I have an application that works but after a while when I debug on my iPhone it hangs the phone and the only way I can recover is a hard reset of the button on the side and the home button.
First of all, could that be because my application has a memory leak?
Here's the code for the application. In particular, I am looking at the BeginInvokeOnMainThread
method. Can someone tell me if they can see if there could be any problems with the way that it is implemented? Also, what's the purpose of the .ContinueWith((arg)
.
namespace Japanese
{
public partial class PhrasesFrame : Frame
{
CancellationTokenSource cts = new CancellationTokenSource();
public PhrasesFrame(PhrasesPage phrasesPage)
{
InitializeComponent();
this.phrasesPage = phrasesPage;
AS.phrasesFrame = this;
Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token).ContinueWith((arg) => { }));
}
public void Disappearing()
{
cts.Cancel();
}
public async Task ShowCards(CancellationToken ct)
{
AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories();
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
}
}
First, let's address your question about .ContinueWith((arg) => { }))
. ContinueWith
tells more code to execute once the original Task
has completed. In our case, the code inside of ContinueWith
will run once Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token)
has finished.
In this case, there is no code inside of ContinueWith
, so we can remove it.
Yes, I can see that this code has potential to freeze the UI.
BeginInvokeOnMainThread
will queue an Action
to run on the Main Thread (also known as the UI Thread). The Main Thread is constantly listening for user input (tapping a button on the screen, pinch-to-zoom, etc.), and if this thread is busy doing a long-running task, it will not be able to respond to a user's input until it has finished; thus your app will appear frozen.
The code await Task.Delay(500);
is being called by the Main Thread. We are thus telling the Main Thread to freeze itself for 500 milliseconds, and looping that indefinitely.
One solution would be to wrap this code in Task.Run
which would put it in a background-thread and free the Main Thread to listen/respond to user input.
Task.Run(async () =>
{
while (!ct.IsCancellationRequested)
{
await Task.Delay(500);
}
}
Only use BeginInvokeOnMainThread
when you need to update the UI. 99% of code can run on a background thread with no problems. The 1%, however, is code that updates the UI; any code that updates the UI must be run on the Main Thread.
If a task that takes longer than the refresh rate of the screen to execute, perform it on a background thread. For example, if the screen's refresh rate is 60Hz, it is updating 60-times per second, every 16.7ms. So if we have a block of code that takes 20ms to execute, we need to execute it on a background thread to ensure that we don't freeze the app and drop any frames.
await Task.Run(() => AS.cardCountForSelectedCategories = App.DB.GetCardCountForSelectedCategories());
First, if you are concerned about a memory leak, you can check for low-memory warnings in the device logs (accessible through XCode), or override the ReceiveMemoryWarning method in your app delegate to log an error.
Secondly, there's nothing obviously wrong with the way you're calling BeginInvokeOnMainThread that would cause a leak. The ContinueWith is a no-op that doesn't affect the operation of the code - I'm guessing it's there to avoid a compiler warning that you're not awaiting the task.
Thirdly, if you suspect that this code is causing a leak, you should use logging and/or breakpoints to confirm that it's behaving as expected. Is the task correctly cancelled when you navigate away from the page? Do you see multiple instances of of the ShowCards task running? If this code turns out to be behaving correctly, then the source of the hang lies elsewhere in your app. For instance, it looks like you're making a database call twice a second - maybe it's not cleaning up resources properly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With