通过接口引用相互引用的实例在基于引用计数的接口实现中使彼此保持活动状态。
弱引用用于打破“让彼此活着”的熊抱。这是通过将一个引用声明为纯指针来规避引用计数机制来完成的。
IFriend = Interface(IInterface)
end;
TFriend = class(TInterfacedObject, IFriend)
private
FFriend: IFriend;
end;
var
Peter: IFriend;
John: IFriend;
begin
Peter := TFriend.Create;
John := TFriend.Create;
Peter.Friend := John;
John.Friend := Peter;
end;
即使 Peter 和 John 超出范围,他们的实例也会保留,因为他们的相互引用可以防止他们的引用计数降至零。
该问题更常见于复合模式(父子关系),其中子项具有对父项的反向引用:
ISomething = Interface(IInterface)
end;
TSomething = class(TInterfacedObject, ISomething)
end;
TParent = class(TSomething)
FChildren: TInterfacedList;
end;
TChild = class(TSomething)
FParent: ISomething;
end;
同样,父母和孩子可以保持彼此在身边,因为他们的相互参考可以防止他们的重新计数下降到零。
这是通过一个解决的weak reference
:
TChild = class(TSomething)
FParent: Pointer;
end;
通过将 FParent 声明为“纯”指针,引用计数机制不会对父级的反向引用起作用。当父级超出范围时,其引用计数现在可以降至零,因为其子级不再将其引用计数保持在零以上。
Note该解决方案确实需要仔细关注生命周期管理。当这些类的“外部”的某些东西保留对孩子的引用时,孩子可以在父母的生命周期之外保持活力。当子进程假设父引用总是指向一个有效的实例时,这可能会导致各种有趣的反病毒。如果您需要它,请确保当父级超出范围时,它会先让子级清空其反向引用,然后再清空其对其子级的引用。