Now the inspector shows MainRect is not null anymore. When I build for Android, MainRect suddenly becomes null, even though it is still not-null in the inspector.
I have to initialize MainRect again in Awake(); in order for it to work in build.
Something is probably resetting that main rect to null in runtime.
Check if that variable is accessed elsewhere (if you’re using VS that is Shift+F12 I think?).
It is as if the Editor resets when I Build. It resets any variables that was set by OnValidate(), and keeps the ones I sat myself.
I use OnValidate() in different situations other than this, and all share the same behavior.
It is more troublesome with private variables too. After many hours with Debug.Log() and Logcat, I traced a simple bug to one of the OnValidate()s that worked in Editor and reset after Build.
Conclusion: If the Editor run fine, but the build is different and bugged; revise all your OnValidate().
I would recommend making an Initialize() function with all the initialization code, and calling it once inside OnValidate() to fill the variables for you, and once in Awake() to avoid this bug when the game is built.
I haven’t encountered this neither at work, neither at home. Most of the bugs with OnValidate occur when somebody forgets to put [SerializeField] on private var or modifies the variable at the run time.
Might be worth making a repro project and sending it to the issue tracker as a bug report.
It’s not a bug.
It won’t initialize for you in the build if Unity didn’t serialize the field by itself.
It’s highly advisable to use Awake to initialize your private variables instead of OnValidate. OnValidate is for Editor time to check the values when someone change them in the inspector. Nothing else.
That’s not quite true. If you dissamble some UI components of Unity’s, you’ll see plenty of component fetches via .OnValidate().
Also, I’d advice using .OnValidate when possible. This is from loading / performance perspective.
Unity does serialize fields, and does it really well.
Private vars aren’t serialized without [SerializeField], that is true. Everything else - not so much.
Here’s a keypoints:
Serialization occurs on play mode start.
Serialization occurs when scripts are reloaded.
Serialization (OnValidate) occurs when any of the fields are modified via inspector.
If it’s neccessary to 100% serialize everything in the whole project, small script can be made to add a hotkey / menu item for the script reload. It can be triggered quite easily by calling reimport on .cs file. That will cause assembly reload + re-serialization.
What we practice is creating a button (Reflection method call for .OnValidate()) for the field that should be fetched via validation, plus a custom drawer. That will ensure that field is fetched correctly, even if the scripts is not being reloaded.
I did send one to Unity, but I knew I must be doing something wrong
Turns out I was missing [SerializeField]. OnValidate() works now as intended, but I still don’t know why !
Using OnValidate with private/public/SerializeField variables works in the Editor, but not in the Build. It works in the Build only if the variable is public/SerializeField.
I still don’t know why …
If you simply write an OnValidate and then never change any value on the component, nothing will be serialized. It’s prone to human mistake. I wouldn’t roll a system like this.
Because in the build it’s not the OnValidate works, it’s the serialization. If you serialize something (enter value in the inspector or change other way and Unity serialize the value, it will be loaded in build, OnValidate does not work in build, you need to cause the serialization in the editor).
The serialization part is not mentioned in the doc. I sent feedback to Unity about that.
Say we have 30 objects in the scene, instead of dragging & dropping them manually to the script, and instead of using FindWithTag at Runtime, I use OnValidate to FindWithTag and fill them during Edit mode.
Because it has nothing to do with OnValidate. Serialization is a separate subject. You’re just mixing up the two and as we can see it’s really not that great if you do that.
Well, it’s up to you how complicated backup systems you’re willing to create just to avoid one command in the Awake method. I don’t recommend to anyone, because as I said, it’s not foolproof. You do however you like.
I thought private variables will be “kept” like public variables. If I understand correctly, Serialization is what keeps the references from getting lost, and since private variables are not serialized, they are not saved.
So private variables are just to be used for runtime only stuff, not with anything related to the Edit mode.
Is that correct?
Serialization is like a snapshot about the object created in memory. If you put a reference in it, it will be saved with the other serializable data.
In Unity, by default the private variables aren’t serialized unless you put the [SerializeField] on the front of them.
The public variables are automatically serialized unless you put the [NonSerialized] attribute in the front of them.
More info here: https://docs.unity3d.com/Manual/script-Serialization.html
Also you can write your own serialization if you wish.
The related issue I have is with the following code:
It keeps thinking _guid is empty and generates a new string guid. It should only do this once, then stick as the _guild is serialised. The emptying of _guid seems to happen on play.
FYI the object this script is on is a prefab and I have multiple instances embedded in the scene
[SerializeField] public string _guid;
void OnValidate()
{
if (string.IsNullOrEmpty(_guid))
{
_guid = Guid.NewGuid().ToString();
}
}