При уничтожении кнопки прослушиватель onClick уничтожается? - PullRequest
0 голосов
/ 19 сентября 2018

Я создаю множество кнопок, которые при нажатии должны вызывать функцию (через слушателя).Но я также очень часто их уничтожаю.Затем эти слушатели также уничтожаются или мне нужно удалить их в противном случае?

Пример:

public void makeButton()
{
    GameObject spawnedButton = Instantiate(prefabButton, prefabButton.transform.position, prefabButton.transform.rotation) as GameObject;   

    spawnedButton.GetComponent<Button>().onClick.AddListener(()=>
    {
        listedButtonClicked(someOtherObjectThatWillNotBeDeleted, spawnedButton);
    });
}

public void listedButtonClicked(GameObject target, GameObject button)
{
    Debug.Log(target);
    Debug.Log(button);
}

... поэтому, когда spawnedButton будет уничтожен, этот слушатель останется?Я создаю и удаляю огромное количество кнопок, чтобы это могло быть актуально для меня.

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

Хорошо, это будет немного глубже.

Учтите это:

Button button;
void Start()
{
     button.onClick.AddListener(Method);
}
void Method()
{
    print("Hey");
}

Все идет хорошо, ваш компонент Button получает "ссылку" на Method, поэтому, когда onClickзапускается, он переходит на адрес метода и запускает код оттуда.

Второй сценарий:

Button button;
void Start()
{
     button.onClick.AddListener(Method);
     Destroy(this);
}
void Method()
{
    print("Hey");
}

Обратите внимание, что я уничтожаю текущий компонент, запускаю его и запускаю onClick, и никаких проблем(?? !!), печатается нормально.

Третий сценарий:

Button button;
string str = "Hey there";
void Start()
{
     button.onClick.AddListener(Method);
     Destroy(this);
}
void Method()
{
    print(this.str);
} 

Вылетает.А теперь для объяснения.Метод ВСЕГДА статичен, компилятор (или создатели) достаточно умен, чтобы считать, что нет необходимости для каждого экземпляра иметь свой собственный метод, а вместо этого иметь шаблон общего метода, в который экземпляр может передать себя.

Методы таковы:

  void ClassName.MethodName(this ClassName); 

Этот параметр перемещается вперед при использовании вызова экземпляра и делается необязательным.Этот параметр действительно доступен в методе, так как вы можете его использовать.Опять же, это не обязательно.

Итак, в первом случае это работает, хотя сценарий больше не существует, это потому, что не было никакого использования какого-либо члена экземпляра.В последнем примере используется str, и поскольку объект больше не существует, он выдает исключение нулевой ссылки.

С учетом обратного.

Если сценарий созданияостается, а игровой объект или компонент Button уничтожается, тогда вы вообще не рискуете.Было бы разумнее очистить событие onClick, но, поскольку оно будет уничтожено, наоборот.Ваш создатель теряет знание кнопки на следующей итерации цикла, в котором создаются все кнопки:

for(i=0;i<10;i++)
{
    GameObject go = null; // new reference added on method stack
    go = Instantiate<GameObject>(btnPrefab); // new instance added to reference
} // go connection is lost right here, a new go added to stack in next iteration
0 голосов
/ 19 сентября 2018

Я нашел ваш ответ здесь более точным

Возможно, я неправильно понял формулировку документов, но AddListener предназначен для добавления нестабильного слушателя.

Но следующее показывает странное поведение (по крайней мере, пока я его не объясню):

 private float myFloat = 10f;
 [SerializeField] private Button button = null;
 void Start( )
 {
     button.onClick.AddListener(MyMethod);
     DestroyImmediate(this.gameObject);
 }
 public void MyMethod()
 {
     Debug.Log("Call " + this.myFloat);
     this.myFloat ++;
 }

лучшая часть в том, что объект, безусловно, исчез, this.myFloat все еще печатается и увеличивается, иУ меня нет постоянного слушателя.

Если я удаляю в Destroy, тогда все идет хорошо.Кажется, AddListener создает ссылку на объект в памяти, и даже запуск GC не будет собирать объект.Я думаю, что использование слабой ссылки вернет ее к жизни.

Что еще лучше, так это то, что если я создам ссылку на мой скрипт выше и вызову значение myFloat, я получу его ?? !!Несмотря на то, что инспектор показывает Отсутствует (Тип) ?? !! ...

Это говорит мне, что у нас есть утечка памяти, если программист не удаляет прослушиватель вручную, пока я не докажу, что ошибаюсь.очевидно.

так .... да и нет.Согласно документации он уничтожен, инспектор говорит, что он уничтожен, но он все еще находится в памяти ... и его можно вызвать.

edit есть метод RemoveListener (), но, похоже,ничего не делать, только замедлить все, и я видел, как это выдает странные ошибки.если вы действительно не беспокоитесь о производительности, ожидайте, что Unity сделает все возможное, удалив их с помощью onDestroy (), и не слишком переживайте по этому поводу ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...