Выпуск / удаление UIViewController в MonoTouch
Насколько я понимаю, нам нужно хранить ссылки на наши объекты Какао при работе с ними в MonoTouch. Причина этого заключается в том, что среда выполнения ObjC может по-прежнему содержать ссылки на объекты, и если у нас нет "ссылок MonoTouch" на них, они могут быть собраны сборщиком мусора, что приводит к EXC_BAD_ACCESS
как только среда выполнения ObjC попытается получить к ним доступ.
Скажем, у нас есть два подкласса UIViewController, VC1 и VC2. Если пользователь нажимает кнопку на VC1, пользовательский интерфейс переходит к VC2, и пользователь может перемещаться вперед и назад. Если я создаю новый экземпляр VC2 каждый раз, когда пользователь переходит на него, то ссылки на старые экземпляры теряются, поэтому они собирают мусор, и в следующий раз приложение вылетает. didReceiveMemoryWarning
распространяется на UIViewControllers.
Как я могу освободить старые ссылки, чтобы мне не приходилось каждый раз использовать один и тот же экземпляр VC2? Dispose
казалось недостаточно.
2 ответа
Насколько я понимаю, нам нужно хранить ссылки на наши объекты Какао при работе с ними в MonoTouch.
Не совсем. Управляемые экземпляры MonoTouch будут сохранять ссылку на собственные экземпляры. Пока управляемый экземпляр существует, собственный экземпляр будет жив (поскольку они подсчитывают ссылки, а MonoTouch не выпускает свою ссылку).
IOW, вам нужно хранить ссылки на управляемые экземпляры MonoTouch, пока требуется их собственная часть.
Причиной этого является то, что среда выполнения ObjC все еще может содержать ссылки на объекты... они могут быть сборщиком мусора,
Собственные (Objective C) экземпляры считаются ссылками, а не мусором. Собственные экземпляры не будут освобождены, пока их счетчик ссылок не достигнет 0 (что не произойдет, пока существует связанный управляемый экземпляр);
Также собственные экземпляры могут содержать ссылки на другие собственные экземпляры. Не у каждого собственного экземпляра есть соответствующий управляемый экземпляр.
что приводит к EXC_BAD_ACCESS, как только среда выполнения ObjC пытается получить к ним доступ.
Этого не произойдет, по крайней мере, так. ОТО, трудно сказать вам, что происходит в вашем случае (без просмотра кода и / или сбоев).
Я подозреваю, что вы удаляете (вручную или нет) ваши управляемые экземпляры до того, как они закончили свою работу. Вот упрощенное из того, что может произойти:
- вы создаете управляемый экземпляр MT.X (например,
UIView
); - это создает и ссылается на собственный X (собственный счетчик ссылок == 1);
- вы переопределяете событие (или добавляете делегата...) `ViewWillUnload'в MT.X (который также существует изначально);
- Вы назначаете экземпляр MT.X другому (управляемому) экземпляру, например
UIViewController
; - родной
UIViewController
добавит ссылку на собственный X (собственный счетчик ссылок == 2); - приложение выполняется счастливо
- вы перестаете иметь ссылку на
MT.X
экземпляр (например, установите переменную вnull
или другой экземпляр); - поскольку нет ссылки на
MT.X
больше сборщик мусора будет располагать управляемым экземпляром, вызываяDispose
который уменьшит ссылку на собственный X (счетчик собственных ссылок == 1). Но нативный экземпляр не будет освобожден, поскольку на него все еще ссылается (не 0) контроллер представления; UIViewController
делает то, что вызывает, изначально,X.ViewWillUnload
(например, он пытается загрузить новыйUIView
);- поскольку
X
до сих пор существует изначально (ref count == 1)ViewWillUnload
который попытается вернуться к управляемому экземпляру... который был удален.
Решение этой проблемы состоит в том, чтобы гарантировать, что вы не утилизируете управляемый экземпляр до тех пор, пока его собственная часть не выполнит свою работу.
В моем приложении такая же ситуация, и GC правильно собирает объекты. Другими словами, я никогда не сталкивался с проблемой, просто обнуляя ссылку на VC и позволяя GC делать все остальное.
Тем не менее, у меня были проблемы при обращении к Dispose
метод, как вы делаете. Кажется, мы не должны делать это вручную. Вместо этого нам следует подождать, пока GC соберет объекты и освободит их ресурсы. База NSObject
класс призван Dispose
в его финализаторе, поэтому все неуправляемые ресурсы будут освобождены после сбора объекта.
Вы также можете позвонить GC.Collect
в некоторых корневых ВК DidReceiveMemoryWarning
метод.