以往的Delphi版本,不支持接口的Weak,和UnSafe的引用,支持對象的Weak, UnSafe,而且僅在Android和Ios平台上支持。
現在Delphi XE10.1 Berlin終於增加了對接口的Weak, UnSafe的支持。
1.Weak
Weak引用,不影響引用計數器,但是如果對象被釋放,Weak引用變量自動清0,來看例子:
type TA=class(TInterfacedObject) end; procedure TForm1.Button1Click(Sender: TObject); var a:IInterface; [weak]aweak:IInterface; begin a:=TA.Create; //創建對象,復制給a,執行完成後引用計數器=1 aweak:=a; //由於aweak定義有[weak]屬性,所以賦值給aweak後,引用計數器依舊為1,但aweak變量的地址被保存到一個weak關聯列表中 Memo1.Lines.Add(Format('Ptr:%d', [NativeInt(Pointer(aweak))])); a:=nil; //由於引用計數器=1,執行此句後,計數器清0,對象被釋放,同時與此對weak關聯列表中所有變量也被賦值為nil,包括aweak變量. Memo1.Lines.Add(Format('Ptr:%d', [NativeInt(Pointer(aweak))])); end;
運行結果
Ptr:16360080 Ptr:0
weak引用非常適合用於兩個對象需要互相引用的情況下,如果以往的引用,將無法讓引用計數器清0.
如下面的例子,互相引用後,兩個對象的計數器都不清0,導致內存洩漏
type ISimpleInterface = interface procedure DoSomething; procedure AddObjectRef (simple: ISimpleInterface); end; TObjectOne = class (TInterfacedObject, ISimpleInterface) private anotherObj: ISimpleInterface; public procedure DoSomething; procedure AddObjectRef (simple: ISimpleInterface); end; ..................... procedure TObjectOne.AddObjectRef (simple: ISimpleInterface); begin anotherObj:=simple; end; ..................... var one, two: ISimpleInterface; begin one := TObjectOne.Create; two := TObjectOne.Create; one.AddObjectRef (two); two.AddObjectRef (one);
這時候在Delphi XE10.1 Berlin下可以用weak引用,來快速方便的解決洩漏問題:
private [weak] anotherObj: ISimpleInterface;
2.UnSafe
unsafe引用,不影響引用計數,但不會向Weak引用那樣清零引用的變量。
type TA=class(TInterfacedObject) end; procedure TForm1.Button2Click(Sender: TObject); var a:IInterface; [unsafe]aunsafe:IInterface; begin a:=TA.Create; aunsafe:=a; Memo1.Lines.Add(Format('Ptr:%d', [NativeInt(Pointer(aunsafe))])); a:=nil; Memo1.Lines.Add(Format('Ptr:%d', [NativeInt(Pointer(aunsafe))])); end;
運行結果
Ptr:42640064 Ptr:42640064
由於Unsafe引用,不影響應用計數器,下面的程序將導致內存洩漏:
procedure TForm1.Button2Click(Sender: TObject); var [unsafe] one: ISomeInterface; begin one := TSomeObject.Create; one.DoSomething; end;