Перейти к содержанию
Fire Monkey от А до Я
  • 0

Как правильно удалять контролы в RunTime?


97mik

Вопрос

Как правильно создавать и удалять объекты в run time?
А то создаю так:

c[r] := TCircle.Create(TabItem1);
c[r].Position.X := 1;
c[r].Position.Y := 1;
c[r].Width := 50;
c[r].Height := 50;
c[r].Parent := TabItem1;

И разрушаю так:

c[r].Free;

То в Win всё ок, а на симуляторе iOS объекты не разрушаются, а просто остаются.

Попробовал так:

c[r].Destroy;

Тогда всё на Win опять всё ок, а на симуляторе разрушается, но при попытке снова создать - приложение крашится.

Ссылка на комментарий

Рекомендуемые сообщения

  • 2
  • Администраторы

Добрый вечер,
 
Главное, что нужно помнить по теме время жизни объектов - это то, что в мобильных платформах (Android и iOS) процесс удаления объектов отличается от поведения на настольных платформах (Windows и OSX). В мобильных платформах появился механизм ARC (Automatic Reference Counting - автоматический подсчет ссылок). Почитать описание (на английском), как это работает можно тут: Apple Developer. Для нас же, это означает, что все объекты имеют поле - счетчик ссылок (RefCount). Когда счетчик ссылок равен нулю, объект автоматически удаляется. Если кто-то присваивает ссылку на объект, то счетчик автоматически увеличивается на 1.

property RefCount: Integer read FRefCount; // Свойство TObject

Можно ошибочно подумать, что это связано со сборщиком мусора. Однако, это не так. При компиляции, компилятор автоматически вставляет в код служебные команды по увеличению и уменьшению счетчика ссылок. Поэтому объект физически уничтожится в тот момент, когда счетчик ссылок станет равным 0. В то время как сборщик мусора, удаляет объекты по своему внутреннему расписанию.
 
Теперь о вашем вопросе. Когда вы создаете объект и указываете ему родителя, автоматически ваш объект попадает как минимум в список дочерних объектов TabItem1. А значит, автоматически счетчик ссылок на TCircle будет увеличен. Когда вы сохраняете ваш объект в массиве, это опять же автоматически увеличивает счетчик ссылок. Поэтому, чтобы удалить объект есть два способа:
 
1. Вызвать метод TObject.DisposeOf. Это форсирует вызов деструктора, но не очищает память выделенную под объект. Это означает, что выполниться код деструктора, TCircle будет удален из списков, все ресурсы, которые окружность захватила будут распущены. Но сама память, которая была выделена из кучи под его хранение будет распущена, только в момент, когда больше не будет ни одной ссылки. Например, так:

c[r].DisposeOf;
c[r] := nil;

2. Убрать все ссылки, которые указывают на ваш объект. Это приведет к автоматическому удалению объекта. Убрать объект из структуры объектов, путем удаления удаления его из родительcкого контроkа Parent = nil, и затем вызывать Free и занилилить уже ссылку на объект в массиве. 

c[r].Parent := nil;
c[r].Free;
c[r] := nil; // Или FreeAndNil(c[r]), в зависимости от типа c.

Если больше ссылок на ваш объект нету, то данный код автоматически удалит объект c[r].

Дополнение от RAD Studio XE6. В этой версии компилятор автоматически после вызова метода Free очистит указатель на объект. По этой причине дополнительно присваивание nil указателю на объект не требуется на мобильных платформах

var
  A: TObject;
begin
  A := TObject.Create;
  A.Free;
  // В этом месте A = nil на мобильных платформах.
  // На настольных платформах: A указывает на мусор
end; 

Чтобы осталась совместимость с настольными платформами, лучше использовать второй подход.

 

P.S. Никогда не вызывайте деструктор напрямую, вызовом метода Destroy.

Ссылка на комментарий
Гость
Эта тема закрыта для публикации ответов.
×
×
  • Создать...