Bascy
Bascy

Reputation: 2089

How to create TDictionary containing weak references to interfaces in delphi

I want to create an Tinterfacedobject that contains (ao) two properties ObjectLinks and ObjectBacklinks. Objectlinks contains interface references to other objects, ObjectBacklinks contains the reverse of those links

Both properties consist of a TWeakIntfDictionary = class(TDictionary) The Backlinks property is maintained in the ObjectLinks.ValueNotify event

To make sure the interface referecnes are removed from the dictionary when the original object is free'd, a notification algorith (same as TFmxObject uses) is put into place

As suspected I'm running into all kinds of circular reference problems when creating so many references to the same interfacedobjects :( but i can't seem to get out of this problem. When the FreeNotification is called from the object being destroyed, everything goes fine until it return fro the FreeNOtification. At that point the .Destroy of the object is called again :-(

 {1 Dictionary of interfaces (using weak references) using Free notification }
  TWeakIntfDictionary = class(TDictionary<int64, IInterface>, IFreeNotificationMonitor)
  protected
    procedure ValueNotify(const Value: IInterface; Action: TCollectionNotification); override;
  public
    procedure FreeNotification(aObject: TObject);
  end;

  implementation

  procedure TWeakIntfDictionary.FreeNotification(aObject: TObject);
  var
    lObj: TPair<int64, IInterface>;
  begin
    //Object is going to be destroyed, remove it from dictionary
    for lObj in Self do
    begin
      if (lObj.Value as TObject).Equals(aObject) then
      begin
        Remove(lObj.Key);
        Break;
      end;
    end;
  end;

  procedure TWeakIntfDictionary.ValueNotify(const Value: IInterface; Action: TCollectionNotification);
  var
    lDestrIntf: IFreeNotificationBehavior;
  begin
      // When a TObject is added to the dictionary, it must support IDestroyNotification
      // This dictionary is than added to the notificationlist of the TObject
    if Supports(Value, IFreeNotificationBehavior, lDestrIntf) then
      case Action of
        cnAdded:      begin
                        lDestrIntf.AddFreeNotify(Self);
                        lDestrIntf._Release;
                      end;
        cnRemoved,
        cnExtracted:  begin
                        lDestrIntf.RemoveFreeNotify(Self);
                      end;
      end
    else
      raise EWeakInftDictionaryException.Create('Object added to TWeakIntfDictionary does not support IFreeNotificationBehavior');

    inherited;

  end;

Anyone know of a existing implementation of a WeakReferences Dictionary? Anyone any suggestions how to solve this ?

Upvotes: 0

Views: 1640

Answers (1)

Bascy
Bascy

Reputation: 2089

Found the solution in the following code

procedure TWeakIntfDictionary.FreeNotification(aObject: TObject);
var
  ...
begin
  //Object is going to be destroyed, remove it from dictionary
  lSavedEvent := FDict.OnValueNotify;
  FDict.OnValueNotify := nil;
  lRemoveList := TList<TKey>.Create;
  try
    for lPair in FDict do
    begin
      pointer(lIntf) := lPair.Value;
      if (lIntf as TObject) = aObject then
        lRemoveList.Add(lPair.Key);
    end;
    pointer(lIntf):=nil; // avoid _release for the last item

    for lKey in lRemoveList do
      FDict.Remove(lKey);

  finally
    FDict.OnValueNotify := lSavedEvent;
    lRemoveList.Free;
  end;
end;

Upvotes: 0

Related Questions