But why I even need to use the returned value? Why the reference that I provided as the second parameter can't be used to modify the object?
Well because this is how it is implemented an how it works ;)
It returns the currently assigned UnityEngine.Object
. If you drag in another one to the according field it will return a different reference afterwards.
Yes, this could have been done using the ref
keyword BUT it is not always desired in all the possible use cases that this call directly changes the reference! You could totally have use cases where you assign the result to another variable than the one you are passing in - maybe do some manual change checks (yes there is ChangeCheckScope
as well but still) or some validation first.
I think they intentionally did not use ref
for that reason to not force everyone to have the passed in variable/field immediately overwritten.
If you want this behavior you can easily implement a custom wrapper around it like
public static class CustomEditorGUILayout
{
public static void ObjectField<T>(string label, ref T obj, bool allowSceneReferences) where T : UnityEngine.Object
{
obj = (T)EditorGUILayout.ObjectField(label, obj, typeof(T), allowSceneReferences);
}
}
then you can do
CustomEditorGUILayout.ObjectField("Old Font", ref _oldFont, false);
This (and the other directly typed) field is mainly used if you have a specific usecase where you do not directly want to assign the result to a property.
For instance when dealing with an EditorWindow
it is sometimes just easier to use those direct fields without the need for any Undo/Redo and serialization management
private Font _oldFont;
...
_oldFont = (Font)EditorGUILayout.ObjectField("Old font", _oldFont, typeof(Font), false);
but it can also used for e.g. validating the input before actually applying it or in other special use cases where you do not want to serialize an object reference (e.g. for having serialized Scene fields were you actually in the background only serialize the path)
Especially when using the upper with serialized fields you have to either make sure to properly handle dirty marking and Undo/Redo yourself or finally apply the value via SerializedProperty
and do
var currentFont = youSerializedProperty.objectReferenceValue;
var newFont = (Font)EditorGUILayout.ObjectField("Old font", currentFont, typeof(Font), false);
youSerializedProperty.objectReferenceValue = newFont;
which is of course quite some overhead (see below).
In most use cases you wouldn't use this at all but rather go through e.g.
[SerializeField] private Font _oldFont;
and then in the editor code do
var fontProperty = serializedObject.FindProperty("_oldFont");
EditorGUILayout.PropertyField(_oldFont);
which automatically uses the best matching drawer for the given property and handles all marking dirty and Undo/Redo for you