Указатель интерфейса релиза Delphi

Я борюсь с интерфейсами в Delphi. Этот вопрос может быть тривиальным, но я новичок в Delphi, так что извините.

У меня есть TreeView с настраиваемыми узлами, которые содержат интерфейс к объекту (по сути, так же, как это предлагается здесь: Сохранение указателя интерфейса внутри древовидного представления узлы).

Проблема в том, что как только я удаляю узел (чтобы перерисовать древовидную структуру) и устанавливаю для переменной интерфейса значение nil (освобождение не работает с интерфейсами по какой-то причине, которую я не совсем понял), происходит самое странное:

В моем объекте, который содержит список, целое число и строковую переменную, строка и список будут установлены пустыми, а целое число останется прежним.

Я не могу это объяснить. Кто-нибудь знает обходной путь или возможную причину такого поведения? Кстати, я использую Delphi 10.2 Tokyo.

Вот мой довольно невзрачный метод уничтожения:

myNode.destroy;
begin
  intf:= nil;// intf holds the interface to the object
end;

Изменить: это упрощенная версия моего кода:

Объект, о котором я говорю: (у меня есть несколько похожих классов, которые выглядят как obj, но немного отличаются, и я не знаю, какой из них будет храниться в интерфейсе, но все они используют эти переменные)

Obj = class(InterfacedObject, IMyinterface)
  count: integer;  //this remains the same
  children: array of ChildObj;  //this will be emptied
  name: string;  //this will be set to ''
  procedure addChild;
  procedure IMyInterface.add = addChild;
end;

Мой настроенный узел дерева:

MyNode = class(TTreeNode)
  Intf: IMyinterface;
  destructor destroy; override;
end;

Внутри моего класса управляет TreeView:

MyForm.ReloadTree;
begin
  if myTreeView.Items.Count > 0 then
  begin
    myTreeView.Items.Clear;
  end
  for I:= 0 to RootObj.Count-1 do
  begin
    myTreeView.Items.AddChild(MyTreeview.Items[0], RootObj.Children[i].name);
    (myTreeView.Items[0][i] as MyNode).Intf := Intf(RootObj.Children[i]);
    //I will proceed iterating over all children and their children, doing 
    //the same process, a level higher in the treeView
    //...
  end;
end;

person zink    schedule 23.09.2017    source источник
comment
о, и моя цель вообще не переделывать объект, так как он мне все еще нужен   -  person zink    schedule 23.09.2017
comment
Просто удалите узел. Внутренние данные обнуляются в деструкторе TTreeNode (по крайней мере, в VCL). Это должно уменьшить количество ссылок на ваш интерфейсный объект и освободить его.   -  person Victoria    schedule 23.09.2017
comment
спасибо за быстрый ответ :) Я пробовал, но результат тот же. Я подумал, что если я переопределю деструктор, то все, что происходит внутри, может не произойти. Но это так   -  person zink    schedule 23.09.2017
comment
Опубликуйте минимальный воспроизводимый пример, показывающий, как именно ваш код (а не чужой код) создает ваши узлы и назначает им интерфейсы.   -  person Remy Lebeau    schedule 23.09.2017
comment
Нам нужен минимальный воспроизводимый пример   -  person David Heffernan    schedule 23.09.2017
comment
Пожалуйста, вставьте свой код в q правильно и не пишите чепуху вроде MyForm.ReloadTree; begin [...], которая даже не скомпилируется, не говоря уже о выполнении.   -  person MartynA    schedule 23.09.2017
comment
Извините, если мой код не удовлетворяет вашим требованиям. Теперь он должен скомпилироваться. Хотя мне больше нечего добавить. Я чувствую, что моя проблема просто требует реструктуризации. @ Дэвид Хеффернан большое спасибо за это прекрасное решение проблемы, которую я связал, кстати.   -  person zink    schedule 23.09.2017
comment
Поддельный код бесполезен. Почему вы не можете это исправить и предоставить минимально воспроизводимый пример, как вас просили?   -  person David Heffernan    schedule 25.09.2017


Ответы (1)


в моем объекте, который содержит список, целое число и строковую переменную, строка и список будут установлены пустыми, а целое число останется прежним.

Это совершенно нормальное поведение. Строки и интерфейсы — это типы, управляемые компилятором. Целые числа нет. Когда объект уничтожается, элементы данных, управляемые компилятором, автоматически освобождаются по мере необходимости, что в случае строк и интерфейсов предполагает обнуление указателей на данные, на которые они ссылаются. Сам содержащий объект не обнуляется полностью, поэтому неуправляемые типы, такие как целые числа, не перезаписываются в памяти.

Теперь, как говорится, я вижу некоторые ошибки в вашей ReloadTree() процедуре.

  1. Ваш цикл for превышает верхнюю границу списка RootObj.Children[].

  2. При вызове AddChild() вторым параметром является string. Вы передаете RootObj.Children[i] в этом параметре. Но в следующем операторе вы приводите одно и то же значение RootObj.Children[i] к интерфейсу при назначении поля MyNode.Intf. string не является интерфейсом. Итак, что именно содержит RootObj.Children[] — строки или интерфейсы?

  3. При назначении поля MyNode.Intf вы всегда получаете доступ к первому узлу в TreeView, а не к вновь добавленному узлу.

person Remy Lebeau    schedule 23.09.2017
comment
Спасибо, это объясняет, почему это происходит. Могу ли я каким-либо образом предотвратить «обнуление» при уничтожении интерфейса? - person zink; 23.09.2017
comment
@zink нет, а зачем тебе вообще? Что вы действительно пытаетесь решить? - person Remy Lebeau; 23.09.2017
comment
о да, вы правы насчет ошибок, мне жаль, что у меня не было моего кода, поэтому я просто быстро перепечатал то, что знал наизусть. Фактический код позволяет избежать всех этих проблем :) - person zink; 23.09.2017
comment
и то, что я пытаюсь сделать, это позволить пользователю управлять данными, которые очень структурированы как дерево, путем добавления, удаления и редактирования объектов obj. Я думал, что смогу сделать это с помощью дерева. Проблема в том, что иногда мне нужно перерисовать свои данные, потому что я хочу изменить цвет ветки, когда некоторые данные, которые она представляет, повреждены. Я не нашел способа управлять этим, кроме удаления и перерисовки соответствующих узлов. Что приведет к тому, что мой объект будет изменен, как описано. - person zink; 23.09.2017