Binding a plain C# object to the lifetime of a scene

Hey folks,
after being recommended the ‘Overthrowing the MonoBehaviour tyranny’ talk, I now try to use as many plain C# objects as possible to manage complexity.
However, I am now encountering an issue related to the lifecycle of objects.
This is my current InCameraDetector, which is supposed to be a Singleton:

public class InCameraDetector {
  private static InCameraDetector _instance;
  private Camera _camera;

  private InCameraDetector(Camera camera) {
  this._camera = camera;
  }
  
  public static InCameraDetector Instance(Camera camera)
   {
       return _instance ??= new InCameraDetector(camera);
   }
 // Methods...
}

This works fine, so that only a single instance of the InCameraDetector is being managed.

There is one problem though, if I go back to the main menu and change the Scene, the Camera gets destroyed while the InCameraDetector doesn’t. This causes an Exception and the InCameraDetector to break.

I was wondering if there is a solid way, to avoid this issue and maybe bind the Singleton to the Scene or something else entirely.

Thank you!

1 Like

See Object.DontDestroyOnLoad

If you want to bind a C# class to the life time of a scene, it needs to be referenced by a monobehaviour.

Ultimately, in this instance, a monobehaviour will still need to manage the C# object. This is Unity after all, and monobehaviours are still needed to make things happen in scene most of the time.

1 Like

You have given little context about your project and needs, which could have given a more correct architectural answer. Anyway, there are 2 ways I see:

  1. Re-registering needed MonoBehaviours when entering the same scene.
  2. MonoBehaviour is the fundamental class in Unity. Why give it up? If you want to save MonoBehaviour between scenes, then use DontDestroyOnLoad as mentioned above. I created a tutorial about correct using of it:

Thank you very much! I also just found out, that I can attach a method to the SceneManager.sceneUnloaded

Is that a solid solution?
I would just remove the reference to the _instance of itself, and thus the object would get garbage collect.

Because as I understand it the issue is that the InCameraDetector references itself, in the current version of the code and doesn’t get GC’d, ever.

Well, the project itself is an AR application and the only Camera we really use, is the one provided by the XROrigin.
About giving up on MonoBehaviours:
I pretty much agree with the speaker in the mentioned talk. MonoBehaviour is quite useful, but is overkill in many situations. The InCameraDetector doesn’t really need to know about all the Lifecycle hooks provided by Unity and should be able to work seperately from Unity itself, as it just checks whether some Object is visible in the Camera.

1 Like

A static instance will live the lifetime of the domain. This means static stuff can live through play mode sessions if you have play mode settings turning domain reloads off when entering play mode.

So yes you would need to manage its lifetime.

So question is, what advantage are you getting here over a monobehaviour? Plain C# objects have their use case (particularly serializable one). But this seems like a case where you should just use a monobehaviour.

1 Like

What does it mean?

  1. In the menu (that doesn’t contain AR stuff) you set some parameters which affect the AR Scene — correct?
  2. Base on these parameters, you load different AR Experience — correct?
  3. Which AR Tracking you use?

You could also pass a destroy cancellation token to InCameraDetector via it’s constructor, if you have some MonoBehaviour attached to the same game object with the camera.

But I personally do agree with the sentiment, that it usually makes life just much easier and more pleasant, if you don’t try to fight Unity, and just use MonoBehavious when it’s convenient to do so :slightly_smiling_face:

1 Like

Alright thanks again! I’ll try rewriting it into a MonoBehaviour :slight_smile:

2 Likes
  1. Pretty much, yes!
  2. Also yes :slight_smile:
  3. We are using the basic ARFoundation AR Session with Position and Rotation, if that is what you mean. :smiley:
1 Like

It looks like you’re always passing in the camera every time you access the instance, and that the instance doesn’t have any fields or other data it holds onto other than the camera.

soooo could this maybe just be a static method that takes a camera? Why do you need the InCameraDetector object?

  1. I mean Plane Tracking, Image Tracking. etc. So, what is it?

P.S. FYI, this is not related to your issue, but useful to operate with AR Foundation when having multiple scene. By Adding SceneUtility and SceneUtilitySetup to your project, you can get rid of the error when switching scenes: “MissingReferenceException: The object of type ‘Camera’ has been destroyed but you are still trying to access it.”