Ответ 1
Это неудачный побочный эффект MonoTouch (который собрал мусор), чтобы жить в мире с подсчетом ссылок (ObjectiveC).
Для получения информации о том, что происходит, есть несколько частей информации:
- Для каждого управляемого объекта (полученного из NSObject) существует соответствующий собственный объект.
- Для настраиваемых управляемых классов (полученных из классов инфраструктуры, таких как UIButton или UIView) управляемый объект должен оставаться в живых до тех пор, пока не будет освобожден нативный объект [1]. Способ, которым он работает, заключается в том, что, когда у нативного объекта есть счетчик ссылок 1, мы не препятствуем тому, чтобы управляемый экземпляр получал сбор мусора. Как только количество ссылок увеличивается выше 1, мы не позволяем управляемому экземпляру собирать мусор.
Что происходит в вашем случае - это цикл, который пересекает мост MonoTouch/ObjectiveC и из-за вышеприведенных правил GC не может определить, что цикл может быть собран.
Вот что происходит:
- В вашем ChildViewController есть sayHiButton. Собственный ChildViewController сохранит эту кнопку, поэтому его счетчик ссылок будет равен 2 (одна ссылка, удерживаемая управляемым экземпляром CustomButton + одна ссылка, принадлежащая встроенному ChildViewController).
- Обработчик события TouchUpInside имеет ссылку на экземпляр ChildViewController.
Теперь вы увидите, что экземпляр CustomButton не будет освобожден, потому что его счетчик ссылок равен 2. И экземпляр ChildViewController не будет освобожден, потому что обработчик события CustomButton имеет ссылку на него.
Существует несколько способов разбить цикл, чтобы исправить это:
- Отсоедините обработчик событий, когда он вам больше не нужен.
- Утилизируйте ChildViewController, когда он больше не нужен.
[1] Это связано с тем, что управляемый объект может содержать пользовательское состояние. Для управляемых объектов, которые зеркалируют соответствующий собственный объект (например, управляемый экземпляр UIView), MonoTouch знает, что экземпляр не может содержать какое-либо состояние, поэтому, как только управляемый код не ссылается на управляемый экземпляр, GC может его собрать. Если управляемый экземпляр требуется на более позднем этапе, мы просто создаем новый.