Thanks for the reply @UmairEm. I do not think you are correct though based on some further investigation I decided to do by setting up a scene as follows.
Test setup
First I created a prefab “MyPrefab” that is not in the scene and attached MyScript.cs as a MonoBehavior as below to capture potential callbacks and object management in the log:
using UnityEngine;
using System;
using System.Threading;
public class MyScript : MonoBehaviour, IDisposable {
private bool disposed = false;
public MyScript() {
Log(Type() + "()", false); // Not on main thread
}
~MyScript()
{
Log("~" + Type() + "()", false); // Not on main thread
Dispose(false);
}
public void Dispose()
{
Log(Type() + ".Dispose()", false); // Not on main thread
Dispose(true);
GC.SuppressFinalize(this);
}
public void Handle() {
Log(GetType() + ".Handle()", true);
}
protected virtual void Dispose(bool disposing)
{
Log(Type() + ".Dispose(" + disposing + ")", false); // Not on main thread
if (disposed) return;
disposed = true;
}
private string Type() {
return GetType().ToString();
}
private void Log(string prefix, bool includeGameObject) {
string msg = prefix + ", thread=" +
Thread.CurrentThread.ManagedThreadId;
// Check flag, if not on main thread this would crash:
// "get_gameObject can only be called on main thread"
if (includeGameObject) {
msg += ": gameObject:" + gameObject.name +
", instanceID=" + gameObject.GetInstanceID();
}
Debug.Log(msg);
}
}
Hence, the only objects I have in the scene is the default “Main Camera”, a single “Canvas” with a single button as only child and a “EventSystem” instance. So I definitely do not have any object in the scene.
Test Procedure
- Restart Unity and open the project
- Click Run in the Editor Click the
- Click the button twice
- Register output written to the log window
Test 1 - No event handler attached
This results in no output during project/scene load.
This result in no output after play button have been pressed.
This results in no output when button is pressed two times.
Test 2 - OnClick of the button bound to MyPrefabs MyScript.Handle() via "Select Object - Assets instead of Select Object - Scene
This results in the following output during project/scene load:
MyScript(), thread=2
This result in the following output after play button have been pressed:
~MyScript(), thread=3
MyScript.Dispose(False), thread=3
MyScript(), thread=1
This results in the following output when button have been pressed two times:
MyScript.Handle(), thread=1: gameObject:MyPrefab, instanceID=7174
MyScript.Handle(), thread=1: gameObject:MyPrefab, instanceID=7174
Conclusion (so far)
Test 1 is pretty trivial, but I still wanted to investigate the object management when the Prefab wasn’t referenced from the Scene. In this case we get no output as one would expect.
In Test 2, we see that the prefab instance is instantiated during scene load. I guess Unity does this via reflection (default constructor) in order to be able to fetch default values of serialized properties or similar. Directly when the application is launched (enter play mode) we see that the object created at load time is destroyed by another thread. The object is then instantiated directly again (on the main thread) by Unity. I guess this is because Unity has determined that the prefab is referenced by the button UI callback (scene reference). However, this instance is not visible in the hierarchy but sure is allocated in memory. As we can see when the button is pressed, the callback works and uses the same instance to handle the event based on the object ID.
I guess this means that:
- Unity automatically detects referenced prefabs (non-instantiated assets) and instantiates a hidden copy on scene load if the prefab is referenced.
- Unity supports callbacks to these hidden object instances which might be beneficial if you have no interest in having the instance as part of the scene and rely purely on run-time interaction with the prefab instance.
If something above seems incorrect or someone can shed more light on these question marks. Please respond to this thread.