Как правильно освободить элемент управления Firemonkey, в данном случае дочернюю форму с родительским?

#android #ios #delphi #firemonkey

#Android #delphi #автоматический подсчет ссылок #firemonkey

Вопрос:

Изнутри обработчика событий самого элемента управления я хотел бы удалить и освободить его.

Типичный вариант использования TFmxObject.Release , не так ли? Однако, похоже, что он работает только под Windows, но не под Android, и этот метод в любом случае устарел.

Я знаю, что «не работает» — это не очень хорошее описание проблемы, но в настоящее время я не могу отладить его под Android. В Windows я вижу, что обработчик событий продолжается корректно после .Release и после его завершения выполняется мое сообщение журнала внутри моего деструктора controls. Под Android приложение зависает.

Когда я использую .Free вместо этого, он по-прежнему работает под Windows (деструктор происходит немедленно, но обработчик не обращается к элементу управления после освобождения), а в Android видимых проблем нет, но деструктор никогда не вызывается, поэтому у меня утечка.

.DisposeOf Эффект такой же, как и при .Release — Windows ok, Android зависает.

Я тоже пробовал MyParent.RemoveComponent(MyControl) , но все это не помогло.

Что еще мне нужно сделать, чтобы освободить все ссылки, чтобы ARC мог выполнять свою работу? Или как еще?

Комментарии:

1. Если вы используете Delphi 10.2 Tokyo, вы могли бы использовать TThread . Принудительно выполнить код позже. TThread.ForceQueue(nil, procedure begin // Dispose of the control end);

2. Это именно то, что .Release делает. Кажется, что на Android это выполняется немедленно, а не позже, и именно поэтому a .DisposeOf без очереди ведет себя так же. Я только что проверил это сам…

3. Я полагаю, еще одна ошибка в RTL. Пожалуйста, отправьте отчет QP.

4. Можете ли вы решить эту проблему, создав анонимный поток и внутри утилизировать элемент управления в методе очереди?

5. @DalijaPrasnikar: неважно, я нашел один: RSP-17841 TThread. ForceQueue не работает в Android

Ответ №1:

TFmxObject.Release используется TThread.ForceQueue внутри, и в настоящее время это не работает под Android (см. Обсуждение выше).

В качестве обходного пути рабочая кроссплатформенная версия для освобождения объекта из его обработчика событий будет

 procedure TForm.CloseBtnClick(Sender: TObject);
begin
  Parent := nil;
  TThread.CreateAnonymousThread(
  procedure
  begin
    TThread.Queue(nil,
    procedure
    begin
      Self.DisposeOf;
    end);
  end).Start;
end;
 

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

Обновление для 10.4 и более новых версий:

Начиная с 10.4 и унифицированное управление памятью DisposeOf теперь эквивалентно Free на всех платформах и Self.DisposeOf может быть заменено Self.Free .

Комментарии:

1. Я бы использовал TThread.Queue() вместо TThread.Synchronize()

2. Это была идея обходного пути @LURD, и мне это не понравилось, но вы убедили меня высококачественным проверенным кодом, спасибо 🙂

3. Извините, я не ответил раньше … был занят … ваш вопрос был в порядке, хотя теперь он еще лучше. Спасибо за редактирование моего ответа 🙂

4. quality.embarcadero.com/browse/RSP-17841 говорит , что эта проблема была исправлена в версии 10.3 Rio