1

Here's a bit of a head scratcher: Building a new app with sqlite, set up a singleton to handle all database functions. Once information is entered, it uses a List added to from the database so a prefab of text fields can be populated on screen. If there is a better way to do this, please let me know.

From the main script:

public void GetOilChangeInfo()
{
    DatabaseManager.Instance.SQLiteInit();
    OilChangeList.Clear(); Clear the list
    OilChangeList = DatabaseManager.Instance.GetOilChangeList(); Make the list from the database
    Debug.Log("How many?" + OilChangeList.Count); //This is correct, I have four entries

    for(int i=0; i<OilChangeList.Count; i++)
    {
        Debug.Log(OilChangeList[i]);  //Shows up as 4 nulls
    }
}

On the Manager Class:

public List<OilChange> GetOilChangeList()
{
    Debug.Log("Function Calls!");
    mConnection.Open();
    mSQLString = "SELECT * FROM " + SQL_TABLE_OIL_CHANGES;
    mCommand.CommandText = mSQLString;
    mCommand.ExecuteNonQuery();
    mReader = mCommand.ExecuteReader();

    while (mReader.Read())
    { 
        OilChangeList.Add(newOilChange(mReader.GetString(0), 
            mReader.GetString(1),
            mReader.GetString(2),
            mReader.GetString(3),
            mReader.GetString(4),
            mReader.GetString(5),
            mReader.GetString(6),
            mReader.GetString(7),
            mReader.GetString(8)));
//Debug.Log(mReader.GetString(0) + mReader.GetString(1) + mReader.GetString(2) + mReader.GetString(3) + mReader.GetString(4) + mReader.GetString(5) + mReader.GetString(6) + mReader.GetString(7) + mReader.GetString(8));
    }

    mReader.Close();
    mConnection.Close();
    return OilChangeList;
}

This gives an odd error, which may be the source of the problem

You are trying to create a MonoBehaviour using the 'new' keyword. This is not allowed.

I have both scripts inheriting from monobehavior. This warning shows up after each entry. Anyone able to help me work this out? Thanks!

MethodMan
  • 18,625
  • 6
  • 34
  • 52
Ken Gordon
  • 195
  • 6
  • 20
  • 1
    Where does the error comme from? I do not see any **new** in your code – Ludovic Feltz Oct 25 '16 at 19:43
  • You have not included the contents of your `newOilChange()` method. Please do so. – Serlite Oct 25 '16 at 19:55
  • And to tell what that error means: You can't create a new instance of a class that derives from `MonoBehaviour` using the **new** keyword. Either you need to use some of unitys ways to get a reference or create a new instance of something or your respective class must not derive from `MonoBehaviour` (e.g. if your class doesn't need to use any of the base functions or has to be present on a gameobject in scene directly). – Gunnar B. Oct 25 '16 at 20:01
  • @ Ludovic For some reason when I copied the code the new ran together with OilChange – Ken Gordon Oct 26 '16 at 16:14

1 Answers1

0

You cannot instantiate classes that inherit from MonoBehaviour yourself. This rule is enforced by Unity Game Engine.

There are several solutions to this problem:

  • Do not inherit from MonoBehaviour. If you do not use any functionalities of MonoBehaviour consider not inheriting from it. Or to tell the short, if you removed the inheritance and your code still worked fine then you should do so.
  • Via Editor: Comment out the line in which you use new keyword. Create an empty gameObject in your scene and attach your MonoBehaviour script to it. Put all the function calls in side Start() method. This way, all of your code will be executed right after you enter play mode (if your empty gameObject is not disabled). If you want full control over when your code is executed you can always use GetComponent<YourClassName>(); instead to get the reference to your MonoBehaviour script.
  • Via Script: Comment out the line in which you use new keyword.

    var emptyGameObject = new GameObject("Empty Game Object");
    var script = emptyGameObject.AddComponent<YourClassName>() as YourClassName;
    script.GetOilChangeInfo();
    script.GetOilChangeList();
    

Update

As for the Singleton part you could do it like this.

public List<OilChange> OilChangeList = new List<OilChange>();
private static DatabaseManager _instance; 
public static DatabaseManager Instance 
{ 
    get 
    { 
        if(_instance == null) 
        {
            GameObject DBM = new GameObject("DatabaseManager");
            _instance = DBM.AddComponent<DatabaseManager>(); 
        }
        return _instance; 
    } 
}

As long as all your team use DatabaseManager.Instance you are safe with 1 and only 1 instance. But there is a workaround which can ruin all your Singleton effort and there is no way to prevent it.

// 1000 instances
for (var i = 1; i <= 1000; i++) {
    GameObject o = new GameObject("Another game object");
    o.AddComponent<DatabaseManager>(); 
}
Cù Đức Hiếu
  • 5,569
  • 4
  • 27
  • 35
  • When monobehavior is removed, I get this error: Assets/Scripts/DatabaseManager.cs(109,37): error CS0309: The type `DatabaseManager' must be convertible to `UnityEngine.Component' in order to use it as parameter `T' in the generic type or method `UnityEngine.GameObject.AddComponent()' – Ken Gordon Oct 26 '16 at 16:32
  • These 3 solutions are independent. Please only use 1 of them. Not all! – Cù Đức Hiếu Oct 26 '16 at 16:34
  • Editor: I was trying to use a singleton model. private static DatabaseManager _instance; public List OilChangeList = new List(); public static DatabaseManager Instance { get { if(_instance==null) { GameObject DBM = new GameObject("DatabaseManager"); DBM.AddComponent(); } return _instance; } } How then should I set this up as you advise? – Ken Gordon Oct 26 '16 at 16:45
  • If you inherit from `MonoBehaviour` I'm afraid you can't implement Singleton design pattern. Because other devs in your team could create multiples empty game objects and attach each with `DatabaseManager` class (which inherits from `MonoBehaviour` I believe). And I'm curious, why do you make `DatabaseManager` inherits from `MonoBehaviour`? Is it really necessary? If you throw away the inheritance things will become a lot easier. – Cù Đức Hiếu Oct 26 '16 at 16:51
  • `MonoBehaviour` means no Singleton and vice versa. I have come across a situation like yours when I purchased the A* path finding asset from the asset store. And in the documentation, they said "Only one instance of `PathFinder` should exist in the scene". `PathFinder` is a class which inherits from `MonoBehaviour`. It means you cannot enforce the `MonoBehaviour` singleton rule from code. The best thing you can do is reminding users from docs. – Cù Đức Hiếu Oct 26 '16 at 17:00
  • Since there are only two scenes, using a gameobject with the script attached would work. I was looking for a lazy instantiation of a singleton class- having it only be used when called for. Might save on memory too. In the game I'm working on, that wouldn't work since there are many multiple scenes. What is the best way to implement a lazy instantiated singleton? – Ken Gordon Oct 26 '16 at 23:18
  • Unless you check and destroy the object if it already exists. – Ken Gordon Oct 27 '16 at 16:16