При работе с интерфейсами в Delphi, разработчики часто сталкиваются с непредвиденным поведением объектов, которое может привести к их преждевременному уничтожению. В данной статье мы рассмотрим проблему, связанную с использованием функции Supports и интерфейсов в Delphi, на примере класса THuman, реализующего интерфейс ICanTalk.
Проблема
В коде, представленном в вопросе, создается объект THuman, который реализует интерфейс ICanTalk. При попытке проверить, поддерживает ли объект интерфейс ICanTalk, с помощью функции Supports, происходит уничтожение объекта THuman. Это происходит, несмотря на наличие ссылки на объект в коде.
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TInterfacedObject;
begin
Obj := THuman.Create('Great guy');
// Если разкомментировать следующую строку, объект будет уничтожен здесь
// if Supports(Obj, ICanTalk) then
(Obj as ICanTalk).TalkTo(Memo1.Lines);
end;
Решение проблемы
Проблема заключается в том, что переменная Obj объявлена как TInterfacedObject, что приводит к тому, что ссылка на интерфейс не используется, и, следовательно, не выполняется подсчет ссылок. Для корректной работы с интерфейсами необходимо использовать переменную, объявленную как интерфейс, а не как TInterfacedObject.
Исправленный код
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: ICanTalk;
begin
Obj := THuman.Create('Great guy');
if Supports(Obj, ICanTalk) then // Объект не уничтожается!
Obj.TalkTo(Memo1.Lines);
end;
Использование переменной интерфейса позволяет корректно обрабатывать ссылки и избежать их преждевременного уничтожения.
Дополнительные замечания
В документации функции Supports указано, что при использовании функции с объектами или интерфейсами происходит изменение счетчика ссылок, что может привести к уничтожению объекта, если счетчик ссылок достиг нуля.
Также стоит отметить, что для компонентов TComponent функция Supports может быть использована безопасно, так как они не наследуют TInterfacedObject и не реализуют собственный подсчет ссылок.
Альтернативное решение
В качестве альтернативы можно использовать класс TInterfacedPersistent вместо TInterfacedObject, что позволит разработчику самостоятельно управлять подсчетом ссылок.
program Project3;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
ICanTalk = interface
['{57E5EF90-EB11-421C-AAFB-18CD789C0956}']
procedure TalkTo;
end;
THuman = class(TInterfacedPersistent, ICanTalk)
public
destructor Destroy; override;
private
FName: string;
public
procedure TalkTo;
end;
...
В этом случае, разработчик должен явно вызывать метод FreeAndNil, чтобы управлять уничтожением объекта.
Заключение
При работе с интерфейсами в Delphi важно понимать механизмы подсчета ссылок и правильно использовать переменные интерфейсов для предотвращения преждевременного уничтожения объектов. Следуя этим рекомендациям, разработчики смогут избежать ряда ошибок и повысить надежность своих приложений.
Вопрос связан с устранением проблемы уничтожения объекта в среде разработки Delphi при использовании функции `Supports` для проверки поддержки интерфейса, что происходит из-за неправильного подсчета ссылок.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.