What is the right flow to cancel UniTask and handle OperationCanceledException? #713
Unanswered
GooseOnSteroids
asked this question in
Q&A
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Im tried to ask that question on unity forum, but didnt get much clarification and Im struggling to find any open projects with real usage of unitasks, so I hope you can help me with understanding best practices.
So Im trying to start using a UniTask and just cant understand them, I have read few guides and watched several videos, but most of examples are dont look like real project use cases.
So case #1:
I want to have next behaviour - screen darkening until it completely black → some heavy task happens → screen become visible again → some task happens.
This is class responsible for screen darkening:
This is method from ScreensManager:
Do I need a try/catch block inside the DoTransition method? It seems so, because even if I don’t intend to cancel this method, it could be canceled if the user force-closes the game during the transition. But when I try to test this and stop game mode in the editor, OperationCanceledException doesn’t occur, which is odd since I’m using GetCancellationTokenOnDestroy as the token. Even odder is that the tracker still shows the unitask as pending after exiting game mode. But if I run the game and let the transition complete, this unitask appears and disappears from the tracker. Am I doing something wrong?
Case #2:
Button of freeze bonus is pressed → button deactivates + countdown timer displayed → in the same time with a previous step gamebahaviour script reacts to click and start countdown of bonus time → after bonus time is finished gamebehaviour return behaviour to regular and ui removes timer and makes bonus button active.
UI methods:
GameplayBehaviour methods:
When the button is clicked, the StartScrollFreeze method is called, which dispatches an event to GameplayBehavior, which triggers FreezeScroll. At the end of execution, FreezeScroll dispatches the appropriate event to ensure the UI timer is stopped and hidden.
You can see that StartScrollFreeze has an empty catch block. This looks silly, but I really have nothing to do when forcibly canceling the timer. If I remove this empty catch block, I’ll see an OperationCanceledException in the console if I try to return to the main menu (disabling the parent object for the game UI) while the freeze timer is active. Is this acceptable, or should I use a different approach to handling calls instead of leaving an empty catch block?
I also thought it would be nice to have:
lines in a finally block, but this causes a missing reference exception if I exit game mode during this bonus. So, I think the finally block should be used very carefully, avoiding any references to objects outside the method’s scope.
However, FreezeScroll from GameplayBehaviour has a finally block, and it works fine when I simply disable its game object when opening the main menu or exiting game mode.
GameplayBehaviour also has this empty catch block because I don’t have the code to execute it, and I’m afraid it will behave like a finally block and cause a missing reference exception if the game is closed.
Can you help me clarify whether my approaches to handling cancellation are bad and what a good approach should look like? Because it seems really wrong to me compared to how the same code could be written with coroutines, without exception handling, and without concerns that the code will continue executing after the game object is disabled.
All reactions