Weird: Adding Event Handler Causes IEnumerator In Different Class To Stop Working

Greetings Wise Coders,

So, I have this weird stuff that’s happening in my code. When I add event handlers to certain events, it will cause IEnumerators in a totally different class to stop functioning.

This is the IEnumerator that shows a button after 4 seconds in the class that is managing the UI.

private IEnumerator PerformGameCompletedProcess(float waitTime)
    {
        while (true)
        {
            if (doGameCompleted == true && gameButtonSummaryDisplayed == false)
            {
                yield return new WaitForSeconds(waitTime);

                ButtonNextTitle.text = buttonNextTitleGameEnded;
                ButtonNextSubTitle.text = buttonNextSubTitleGameEnded;
                ButtonNext.SetActive(true);
            }

            yield return null;
        }
    }

This is the code (that sends the game data to be saved in the database) on a totally unrelated class that is responding to the same event:

void OnFinalGameplayTelemetryAvailable(GameplayTelemetry finalTelemetry)
    {
        SaveGameplayDataEvent?.Invoke(finalTelemetry);
    }

    void SubscribeToEvents()
    {
        ControllerGameplay.ProcessFinalGameplayTelemetryEvent += OnFinalGameplayTelemetryAvailable;
    }

Basically, when the game ends, the UI class responds to the event by setting a flag that the IEnumerator uses to show the button in 4 seconds or so. The code that send the data to the database responds to the save event and sends the data.

For some reason, if I comment out the assignment of the handler that sends it to the database for saving, the IEnumerator in the class managing the UI works. If I don’t comment it out, the class does not work.

I have searched online and still have not found an answer. Any help would be greatly appreciated it.

Thanks.

There’s a lot of missing context here that makes it difficult to answer this question, but any of the following will cause a coroutine to stop executing:

  • Deactivation of the GameObject the coroutine was started from
  • Disabling of the script the coroutine was started from
  • Destruction of the GameObject or script the coroutine was started from
  • Loading a new scene (which causes the destruction of the GameObject/script the coroutine was started from)
  • Explicitly calling StopCoroutine or StopAllCoroutines.
  • If the coroutine is waiting on a WaitForSeconds, setting Time.timeScale to zero will stop the coroutine from continuing.

So check your setup for any of these things that could cause the issue.

Thanks for your response. There is no deactivation or disabling of any of the scripts or their related objects. Also, there are no object destructions, and no new scenes are loading. Also, time.timeScale is never even referred to within the application and the StopAllCorountines are called after.

When I comment out the additional event handler assignment in the data saving script, it works fine. When I uncomment it, while the database script works and save the data in response to the event, the UI script wherein the flag is set for the IEnumerator ceases to work. The two do not even seem related to me.

It’s unclear to me when and where all of these methods are called, which scripts they belong to, where the coroutine is started, where it is stopped, when these events are fired etc… so it’s hard to comment further without knowing those things. it seems likely that if you have a StopAllCoroutines call in your code that could be the culprit. Have you tried logging when that code is running?

I see.

Perhaps this may help:

  1. The timer class fires an event that the game has ended. The argument in this event is summary data (e.g. score, total game time, etc.) from the game.

a. The UI script processes this event by setting a button display flag to true. The ienumerator in this class, when the button display flag is true, shows a game completed button in 4 seconds.

b. The data processing script also handles this event. It sends the data to the database to be saved.

What is happening is that when I connect the event handler for point b above, point a does not work. Both a and b are on different objects.

The issues you mentioned would not seem to show up only if certain event handlers are connected or not. The only reason that the code works or doesn’t is when I don’t or do connect certain event handlers. Nothing else is changed so that the only difference is whether the event handler in b is connected.

What do you mean by logging when the code is running? I used Debug.Log to display the value of the flag and it turned out to be what it should be. Are you talking about something else?

You said that there is a StopAllCoroutines call somewhere in your code. I meant to log when that is called. Are you calling it when the game ends?

One possibility is that event handler B is throwing an exception. if that is the case, it may stop other handlers from being executed.

I wonder if your point about event handler B throwing an exception might be a factor. Any idea how I can find out. Nothing shows up in the editor. I am using Unity3d on a Mac and using Visual Studio for Mac.

Also, you mentioned logging when the StopAllCoroutines is called, how would I do that?

The reason I don’t think the StopAllCoroutines is related is because the only thing I change is the assignment of the event handler. I will check to make sure the event handler managing the data saving is not doing something else.

It could matter if that new event handler is triggering the StopAllCoroutines call.

You could wrap the code in the handler in a try/catch block and log something, though I would expect the exception to bubble up and show an error in the console.

THANK YOU!!

So, it seems you are on to something. I surrounded it in a try/catch block, and immediately it told me my data reader was closed. So it was throwing an error, but the console did not report it. I am going to try to fix that to see if it works.

So, I guess it would be fair to say if there is an error in an event handling, does it stop all other events from running, or does it somehow affect other event handlers on the same event?

1 Like

I can’t find an “official” Microsoft source for it, but if you Google around a lot of people recommend making sure every event handler has a try/catch. For example: https://stackoverflow.com/questions/8744480/exception-management-practices-inside-event-handlers

It stops the event execution. When you fire an event in C#, all of the subscribed event handlers are executed one by one, but if one of them throws an exception, the whole process stops. So if A, B, and C are listening, and B throws an exception, C will never get a chance to run. I think it’s a pretty unfortunate aspect of events in C#, especially if it is silent as your exception seems to be. Not sure if that’s a C# problem or a Unity problem.

Personally, I don’t bother with try/catch inside event handlers unless I’m doing something where I expect errors. Doing IO operations like writing/reading files is absolutely a case where you should have a try/catch, because there is always the possibility for an exception there, even if you do everything right as the programmer (what if the user unplugs the hard drive from the computer while you’re writing a file??).

Thanks for the insight. You have helped me out a lot. Now on to fix the exception. I am actually using SQLite and its telling me the datareader is closed, so I will be needing to figure out how to fix that.

Thanks again.

1 Like