13.4.2 弱引用是系统托管的
弱引用的托管是一个非常重要的内容。换句话说,系统会在内存中保存一个弱引用列表,当对象被销毁时,系统会检查是否有任何弱引用指向该对象,如果有,系统会将实际引用赋值为 nil,即实际外部引用指针等于 nil。这意味着弱引用会产生运行时成本。
与传统的引用相比,托管的弱引用的好处是可以检查接口引用是否仍然有效(这意味着它所引用的对象已被销毁)。但这也意味着,在使用弱引用时,应始终在使用前测试它是否已被赋值。
private
[weak] MySimple: IMySimpleInterface;
还有一个按钮为该字段分配一个引用,并使用它,确保它仍然有效:
procedure TForm3.BtnGetWeakClick(Sender: TObject);
var
MyComplex: IMyComplexInterface;
begin
MyComplex := TMyComplexClass.Create;
MyComplex.GetSimple.DoSomething(False);
MySimple := MyComplex.GetSimple;
end;
procedure TForm3.BtnUseWeakClick(Sender: TObject);
begin
if Assigned(MySimple) then
MySimple.DoSomething(False)
else
Log('Nil weak reference');
end;
除非修改代码,否则 "if Assigned "测试将失败,因为第一个按钮事件处理器会创建并立即释放对象,这样弱引用就会变成 nil(因为它现在无效)。但由于弱引用是托管的,编译器会帮助你跟踪它的真实状态(与对象引用不同)。
13.4.3 Unsafe
属性
在某些非常特殊的情况下(例如在创建实例时),函数可能会返回一个引用计数为零的对象。在这种情况下,为了避免编译器立即删除该对象(在它有机会被赋值给变量之前,这样它的引用计数就会增加到 1),我们必须将该对象标记为不安全对象。
这意味着必须暂时忽略对象的引用计数,以使代码安全。这种行为是通过使用新的特定属性 [Unsafe] 来实现的,只有在非常特殊的情况下才需要使用这种特性。
语法如下:
pascalCopy codevar
[Unsafe] Intf1: IInterface;
[Result: Unsafe] function GetIntf: IInterface;
在通用库中实现构造模式(如工厂模式)时,使用该属性是有意义的。
注解:为了支持现在已废弃的ARC内存模型,System单元使用了一个
unsafe
指令,因为它无法在属性定义之前(同一单元的稍后部分)使用该属性。在该单元之外的任何代码中都不应该使用该指令,而且现在也不再使用了(你可以在 $IFDEF 指令中看到它)。