http://docwiki.embarcadero.com/RADStudio/Seattle/en/Automatic_Reference_Counting_in_Delphi_Mobile_Compilers#Weak_References

Weak References

Another important concept for ARC is the role of weak references, which you can create by tagging them with [weak] attribute. Suppose that two objects refer to each other using a field, and an external variable refers to the first. The reference count of the first object will be 2 (the external variable, and the second object), while the reference count of the second object is 1. Now, as the external variable goes out of scope, the two objects' reference count remains 1, and they remain in memory indefinitely.

To solve this type of situation, and many similar scenarios, is to use a weak reference to break the circular references when the last external reference goes out of scope.

A weak reference is a reference to an object that does not increase its reference count. To declare a weak reference, use the [weak] attribute, supported by the Delphi mobile compilers.

Given the previous scenario, if the reference from the second object back to the first one is weak, as the external variable goes out of scope, both objects are destroyed. Here is an example of this situation:

type
  TMyComplexClass = class;
 
  TMySimpleClass = class
  private
    [Weak] FOwnedBy: TMyComplexClass;
  public
    constructor Create();
    destructor Destroy (); override;
    procedure DoSomething(bRaise: Boolean = False);
  end;
 
  TMyComplexClass = class
  private
    fSimple: TMySimpleClass;
  public
    constructor Create();
    destructor Destroy (); override;
    class procedure CreateOnly;
  end;

In the following code snippet, the constructor of the complex class creates an object of the other class:

constructor TMyComplexClass.Create;
begin
  inherited Create;
  FSimple := TMySimpleClass.Create;
  FSimple.FOwnedBy := self;
end;

Remember that the FOwnedBy field is a weak reference, so it does not increase the reference count of the object it refers to, in this case the current object (self).

Given this class structure, we can write:

class procedure TMyComplexClass.CreateOnly;
var
  MyComplex: TMyComplexClass;
begin
  MyComplex := TMyComplexClass.Create;
  MyComplex.fSimple.DoSomething;
end;

This causes no memory leak, given that the weak reference is properly used.

As a further example of the use of weak references, note this code snippet in the Delphi RTL, part of the TComponent class declaration:

type
  TComponent = class(TPersistent, IInterface,
    IInterfaceComponentReference)
  private
    [Weak] FOwner: TComponent;

If you use the weak attribute in code compiled by one of the desktop Delphi compilers, the attribute is ignored. Using DCC32, you have to make sure that you add the proper code in the destructor of an "owner" object to also free the "owned" object. Calling Free is allowed, although the effect is different in the Delphi mobile compilers. The behavior is correct in both in most circumstances.

Note: When an instance has its memory released, all active [weak] references are set to nil. Just as a strong (normal) reference, a [weak] variable can only be nil or reference a valid instance. This is the main reason why a weak reference should be assigned to a strong reference before being tested for nil and dereferenced. Assigning to a strong reference does not allow the instance to be released prematurely.
var
  O: TComponent;// a strong reference
begin
  O := FOwner;  // assigning a weak reference to a strong reference
  if O <> nil then
    O.<method>;// safe to dereference
end;
Note: You can only pass a [Weak] variable to a var or out parameter that is also marked as [Weak]. You cannot pass a regular strong reference to a [Weak] var or out parameter.
posted on 2016-01-16 17:02  lypzxy  阅读(176)  评论(0编辑  收藏  举报