Be careful about run order of Awake functions

Hi
I intend to explain why run order of Awake functions is vital because it can cause weird behaviours.
I don’t know the reason why unity executes Awake functions without any order.So if awake functions depend on each other, in every execution, you may see different behaviours

3 Likes

Objects should initialize themselves in Awake() and talk to other objects in Start().

The sequence of Awake() being called before Start() is guaranteed every time, but the order in which a particular script gets the call is sequential and can only be forced consistent by changing the Script Execution Order.

16 Likes

You could use events to daisy-chain the initialization in the order you want I suppose, but it’s far easier to just divide the job between Awake and Start as @LaneFox said.

1 Like

yes but in singleton design pattern you initialize them in Awake. They can depend on together
I know we can use the following ways:
1- lazy initialization
2- give orders with Edit->Script Execution order
3- initialize them in one main entry point
4- use service locator

1 Like

and why does unity implement them like this,random orders!

It is not random, as already stated. Study the links if it’s not clear to you.

1 Like

It’s not a random order.

It’s an undefined order.

From my practice, the order appears to be the order of the GameObject’s the components are attached to in the hierarchy, from top to bottom. Child GameObjects are called starting deep and backing out. (Execution Order taking precedence over this of course)

But Unity has this order undefined, because they don’t want you relying on any defined order. If they did define it, then they could never change it. If down the line they wrote a faster/efficient initialization algorithm, but required changing the order, by defining it they wouldn’t be able to change.

So instead they tell us users to not expect it to be in any particular order. And to use Awake/Start to do any ordering.

In the case of Singletons… as you your self brought up, you have 4 alternative ways to deal with the ordering issues.

Personally I have foregone singletons for the most part. In my latest version of spacepuppy I have only 1 true singleton left. And I have migrated everything else to a service locator system.

5 Likes

So you say it is not random and in a build version or editor they are called the same?
Because I see myself that my game was executed differently in build and editor
In editor it was completely true and expected
When I added the singleton in the execution order correctly, it was run appropriately in build as well!

1 Like

Different builds may have different orders.

My point is that it’s not random.

It’s undefined.

Unity doesn’t just randomly select objects to initialize. There’s a method to the madness behind the scenes. We just don’t know WHAT that method is. And that method may vary from target platform to target platform. I can see different algorithms being used because different ones may be better optimized for specific platforms.

2 Likes

I didn’t change the platform (Always android). Thank you

Android is a different platform than the editor running on Windows/Mac/Linux.

I’m also not saying that it does do this, I’m saying that I can understand why it could do this.

In the end… it’s undefined, so all of our guesses are the best we can say.

The solution is to design scripts that work and support each other in the given circumstances. The documentation explains that you are guaranteed to get every Awake() call before Start(), and you are guaranteed to get all Start() calls before any Update() call. You also have the option of forcing a sequence of scripts to get their calls via the Execution Order panel.

That is enough structure to guarantee safe initialization and communication of scripts, you just have to design within those features.

5 Likes

This. You can’t say that often enough. :smile:

@mahdiii
Even when Singletons are used, you can still resolve most of the dependencies if you use Awake and Start correctly.

Anyway, similarly to @lordofduct , I also decided to design my modules and systems without singletons. There’s at most just one singleton in my current framework and that’s just for the common quick start (it’s basically the application’s root “container” or context that provides access to all modules / systems - either instantly or lazily, i.e. on demand). It doesn’t even need to be a singleton.

Early in the days I was kind of in love with singletons. It was my very first widely-used design pattern. It was easy to access the instance from literally everywhere (which is actually a problem), easy to code (there are some common pitfall in Unity but it’s not difficult either) and people who read the code immediately understand what’s being accessed there and can adapt that.

But after

  1. further extensive research about the pattern and also relevant topics (such as an overuse / misuse of statics)
  2. various approaches to code singletons in a more flexible way
  3. much unit testing

they always revealed the ugliness and pain that comes with singletons in big projects once they’re introduced on higher layers. There are still ways to work around some of the major problems, but I personally wouldn’t use these anymore.

This also changed my mind about DI and IOC in general, as I first thought it was just one of these hypes and put it aside evily smiling at it. I still don’t use DI frameworks (rather my own system which adapts a few ideas), but it’s a powerful approach to eliminate some major design flaws when it comes to resolving dependencies.

2 Likes

whats so hard about this, setup the internal state of your object in Awake, then if you need to talk to other objects do it in Start

3 Likes

My problem was not about Awake Start, it was about OnEnable and Awake.
See like below:

public void OnEnable(){
   CEventManager.GetInstance().AddListener("EventName",OnEvent);
}
public void OnDisable(){
      CEventManager.GetInstance().RemoveListener("EventName",OnEvent);
}

You know that OnEnable can be executed before some Awakes(other Awakes that don’t belong to the gameobject)

Maybe it was better to write:

public void Start(){
   CEventManager.GetInstance().AddListener("EventName",OnEvent);
}
1 Like

This is actually an issue I ran into a long time ago. I created my own message called ‘OnStartOrEnable’:

2 Likes

This is the first time you’ve mentioned OnEnable in this thread. For future reference, perhaps you could describe the entire problem instead of expecting us to read your mind.

It’s true that A’s OnEnable might be called before or after B’s Awake if both are in the scene at the start of the scene. So if CEventManager’s instance is null because its Awake hasn’t been run yet, that OnEnable might break. As mentioned, you simply need to design within the system that exists.

Perhaps something like this would work. This will add and remove the listener as designed in your first attempt, but will also work if this object runs OnEnable before CEventManager’s Awake.

 bool listenerAdded = false;
public void OnEnable(){
if (CEventManager.GetInstance() != null) {
   CEventManager.GetInstance().AddListener("EventName",OnEvent);
listenerAdded = true;
}
}
public void Start(){
if (!listenerAdded) {
   CEventManager.GetInstance().AddListener("EventName",OnEvent);
listenerAdded = true;
}
}
public void OnDisable(){
      CEventManager.GetInstance().RemoveListener("EventName",OnEvent);
listenerAdded = false;
}
6 Likes

I will point out… this is similar to a conversation we all had in another thread.

Mahdii you have a knack for leaving out key information about the conversation (like the use of OnEnable, this is the first you mention it in this conversation). This confuses everyone as you talk about things in strange absolutes that don’t apply to the context up to the point you mention new information.

3 Likes

Oh, you did not say that explicitly in your first post. Now that’s some information you should have added earlier.

That’s true, but a simple “yes, do it like that” is not always sufficient. You may still want to add/remove when enabling/disabling the component.
There’s a little more to that but it’s not that tricky either, I’ve seen some solutions already on the forums.

*EDIT
Just saw @lordofduct has already linked his approach. You may wanna look at that.

1 Like

How nice would it be if there was :
Awake (unspecified order)
Awoken (now all are awake and can talk)
OnEnable (now i need to do something)
Start …
Why specifically does Unity do OnEnable before Start ?
Usually Onenable will be needed often. With values that may depend on other scripts having executed.
So why iniztialize in start ???
Or at least … as above. Make a prewarmup = awoken…