なぜTInterfacedObjectはごみの子孫が収集されませんか?
-
20-08-2019 - |
質問
私はTInterfacedObjectはに基づいて、クラスを持っています。私はTTreeNodeのDataプロパティに追加します。
TFacilityTreeItem=class(TInterfacedObject)
private
m_guidItem:TGUID;
m_SomeOtherNode:TTreeNode;
public
end;
私は、このオブジェクトの多くのインスタンスを作成&それらは参照カウントしているので、私はそれらを解放する必要がないことを前提としていました。それは便利になると思います。
これをチェックする際にしかし、私はReportMemoryLeaksOnShutdownオンになり、彼らは結局解放されていないいます。
これらのオブジェクトは、メインフォーム上に配置されていますフレームに作成されています。メインフォームのFORMCLOSEで、私はすべてのオブジェクトが解放されなければならないようなツリーノードをクリアします。
何が起こっているか?
あなたの助けをありがとう!
解決
TInterfacedObjectは自身がカウント参照されていない、唯一のインターフェースです。あなたは基本的にあなたの参照カウントメソッドを自分で実装する手間を省くTInterfacedObjectはを使用して、インターフェイスを実装することができます。残念ながら、それはまだあなたのケースでは動作しません:それはインタフェースとしてではなくポインタとして宣言されていないため、コンパイラは、TTreeNode.Dataプロパティにインターフェイスを割り当てていることを知りません。だから、奇妙なあらゆる種類のものが発生します。
MyInt := TFacilityTreeItem.Create; // ref count = 1
// Node.Data := MyInt; // won't compile
Node.Data := pointer(MyInt); // no interface assignment, ref count stays 1
...
end; // ref count reaches 0, your object gets freed
とすぐに.DATAプロパティを介して、あなたのオブジェクトにアクセスしようとして、あなたがアクセス違反を取得します。
だから、この場合はインタフェースを気にしないでください、あなたはそれが動作するように得ることができるが、それは価値があるよりもはるかに多くの努力になります。
他のヒント
あなたはインターフェイスとしてフィールド/変数を宣言する必要があります。
IFacilityTreeItem = IInterface
end;
TFacilityTreeItem=class(TInterfacedObject, IFacilityTreeItem)
private
m_guidItem:TGUID;
m_SomeOtherNode:TTreeNode;
end;
var
Item: IFacilityTreeItem; // Variable as Interface
begin
Item:= TFacilityTreeItem.Create;
...
end;
あなたのフィールドにアクセスするには、ゲッタとセッタで、IFacilityTreeItemインタフェースでプロパティを宣言する必要があります。
、あなたが得ることができますこれは、インターフェイスで動作するが、TTreeNodeのデータプロパティがポインタであるので、いくつかのより多くのコードを取ります。それを行う方法を疑問に思う人にとって、このリンクには例がありますTListItemのためにそれを行うにはどのように(それはTTreeNodeのためにほとんど同じです)。また、インタフェースと、後続のセクションを読んでそれが役に立つかもしれませんそのページの参照カウントに関するセクションます。