Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Is it safe to use Awake for hooking up references

Discussion in 'Scripting' started by liortal, Jan 8, 2015.

  1. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,555
    Hey,

    I'd like to know when is it safe to connect game object references.

    By that i mean:

    1. Call GetComponent<T> to assign component references.
    2. Call GameObject.Find, etc
    In Awake, I remember reading somewhere that there's a chance the other component was not added yet (its Awake wasn't called yet).

    Is it OK to assign component references in Awake?

    The Awake documentation page mentions:
    What does that mean? what should you NOT do in Awake ?
     
    aparajithsairam likes this.
  2. hakankaraduman

    hakankaraduman

    Joined:
    Aug 27, 2012
    Posts:
    353
    Also a noob here but have an opinion, maybe it will help.

    I use GetComponent<>() methods in awake, also in the scene i put GameObjects to the slots if I used any public GameObject field.

    In the start function, If I need, I reference to other scripts variables. This way I don't get nullreferenceexception when i reference to other fields and use them
     
  3. inko

    inko

    Joined:
    Nov 29, 2013
    Posts:
    143
    Well, you kinda answered your own question, didn't you?. In the documentary it also says:
    And while it is true that in some very rate cases an reference gets assigned too late due to delegate trickery or stuff like that you usually don't have to worry about that.

    [EDIT] Little side note: Setting references is actually pretty much exactly what Awake is for since it's as close to a Monobehaviour construcor as you get.
     
    Last edited: Jan 8, 2015
    Mycroft likes this.
  4. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    You can use Awake for this, but it's better to do it in Reset. Add it to an interface, and do what you like with it. I call all of them with my menu item Assets/Initialize Scene.
    Code (CSharp):
    1. namespace UnityEngine {
    2.     public interface ISceneInitializable {void Reset();}
    3. }
    Awake is primarily useful for subscribing to events, in my experience.

    Don't use public fields for anything serialized. It was a bad decision on Unity's part to make public and [SerializeField] be tied together.
     
    SolidAlloy likes this.
  5. hakankaraduman

    hakankaraduman

    Joined:
    Aug 27, 2012
    Posts:
    353
    I recently read a document which says using

    [SerializeField]
    private FieldType FieldName;

    is better than using public fields. Is that what you mean? Though I read that, I'm not using it because it looks like a bit more code. My bad :(
     
  6. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Each GameObject and all of its component exist before awake is called. This means you can call GetComponent to your hearts content.

    What you shouldn't do is use any variables on any components. You have no guarantee that these variables are ready, as you can't tell if Awake has been called. Some examples may help.

    Code (CSharp):
    1. MyComponent myComponent;
    2. Float someValue;
    3.  
    4. void Awake () {
    5.     // This line is okay
    6.     myComponent = GetComponent<MyComponent>();
    7.     // This is not okay
    8.     myFloat = GetComponent<MyComponent>().someValue;
    9. }
     
    Dodd_, Doranna, lym597972642 and 4 others like this.
  7. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Using SerializeField is good advice. In C# you don't have to write private, so its not that many extra key strokes.

    public allows any script to access a variable. It can lead to unexpected bugs and dependency issues for variables that are designed to be initialised in the inspector, but not changed during game play. In general you should have as few public variables as possible. Each public variable should have a defined purpose for other classes to interact with your class.
     
    Hiddensquid_ likes this.
  8. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    My recommendation isn't really about the scope; I'm just saying that it was not good to make any access modifier (public, private, etc.) automatically invoke [SerializeField]. It leads to less experienced people (like the people who first made Unity, and the decision itself) using that access level, just to get things into the Inspector.

    If the Inspector updated properties (not just fields), I'd have to reevaluate this, but because it doesn't, here's what my team does:
    If you know that you need a serialized field, treat it as a backing field for a property. In addition to accessing it via the property blocks, permit yourself to set the field's value in the Inspector, if it makes sense to do so. Otherwise, use [HideInInspector].
    • Never serialize a field by making it public. Use [SerializeField], and only on private or protected fields.
    • If the backing field is visible in the Inspector, and you want to change the name of the property, you should employ FormerlySerializedAsAttribute.
    Example of how what's serialized, and what you want, aren't always the same thing.
    Code (CSharp):
    1. [SerializeField] NullableBool _switch; bool? @switch {get {return _switch;}}
    NullableBool is implicitly convertible to bool?. NullableBool only exists because Unity doesn't serialize nullable types.

    A lot of what I serialize doesn't even need to be set from code, so only having a getter is very common for me. Setting the value is what you do in the Inspector.
     
    milesizzo likes this.
  9. bhunterd

    bhunterd

    Joined:
    Oct 6, 2016
    Posts:
    27
    When you are using Awake() and object is not an anctive at the game start the Awake of this object will not be called untill you set object active but if you use public variables objects will be referenced. That the problem of using Awake() for initialization I had found.
     
  10. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,911
    The note about Awake/Start in the docs isn't new information. All you need to know is all Awakes run, then all Starts run. The note is explaining how you can use Start() to make sure one thing runs after another, in different scripts. The "random order" part is also old. You can set the Script Execution Order now. If you don't, the order might seem random.

    The thing about public/private is it has no effect on how the program runs. If you never want to use a variable from outside, but it's public, it clutters up the dropdown a little. But making it private and adding getters/setters, which is what most people do, isn't any better.
     
    ROBYER1 likes this.