引用计数 ARC 在 delphi 下非常令人困惑,它使开发变得更加困难,因为它设计得很糟糕(在 delphi 下)。
首先它是在 RTL 中构建的,它与 String 非常相似。它适用于平台(firemonkey)和操作系统(仅适用于 android/ios/unix)。因此,如果您想构建还针对窗口的多平台代码(很可能,至少只是为了调试您的代码)无论如何您都需要继续尝试 ... finally .. end;(是的我说你,非常糟糕的设计)。所以忘记你没有 .free 的例子,除非你想在移动设备下调试(祝你好运,每次编译 3 分钟,这根本不可能)
注意:为了让您的代码尽可能地兼容,一个很好的获取规则是将所有 .free 替换为 .disposeOF 后跟 nil,因为在移动设备下, free 是一个无操作操作,您的对象不会被破坏,并且可以在非常意外的时间被破坏(或者在最坏的情况下永远不会被破坏,如果您使用例如 TTask 很常见)。这些场景并不少见,特别是如果您经常使用在后台捕获到您的对象的匿名过程(对过程的引用)。
请始终牢记,循环 ref 很容易满足,而且相当
很难发现
.
你也必须知道(你没有问,但我扩展了一点答案)它们是delphi Tobject,java object,IOS object C object和Interface。所有人都有自己的规则,让每个人都感到困惑,最后没有人真正知道它是如何工作的(是的,ARC 糟糕设计的一部分也是它给人的困惑),甚至 emb 开发人员在他们的 delphi 源代码中也会出错,寻找例如这个问题:delphi + ios: release / retain and reference counting with objective-c object 这很简单,但没有任何答案
ARC 和 Objective-C 封装的对象
Delphi NextGen 编译器为所有 Delphi 对象实现自动引用计数 (ARC)。编译器将为您管理 TObject 的 __ObjAddRef 和 __ObjRelease 的逻辑。 Objective-C 代码使用相同的逻辑来调用保留和释放。不幸的是,由导入包装类和上面讨论的接口表示的 Objective-C 对象没有 ARC。在处理 Objective-C 对象时,您必须在正确的位置调用 retain 并释放自己。
ARC 和 JAVA 对象
在纸上它必须有效,但我个人不相信它,例如,如果你在循环中这样做:
for i := 0 to 100000 do begin
aJstring := StringToJstring('a text');
aStr := JstringToString(aJstring);
end;
通常这必须在正常世界中毫无问题地运行,但在 delphi 下,它会崩溃:(但无论如何在这里你没有 .release 所以你没有选择(除了将变量分配给 nil)。但是,当您选择为什么我建议始终使用 .disposeOF 后跟 nil 时,您可能会赢得数天/数周/数月的开发,从而避免一些讨厌的错误。
注意:当我想销毁一个对象时,我会调用这个函数:
{******************************}
Procedure ALFreeAndNil(var Obj);
var Temp: TObject;
begin
Temp := TObject(Obj);
if temp = nil then exit;
TObject(Obj) := nil;
{$IF defined(AUTOREFCOUNT)}
if AtomicCmpExchange(temp.refcount{Target}, 0{NewValue}, 0{Compareand}) = 1 then begin // it's seam it's not an atomic operation (http://stackoverflow.com/questions/39987850/is-reading-writing-an-integer-4-bytes-atomic-on-ios-android-like-on-win32-win6)
temp.Free;
temp := nil;
end
else begin
Temp.DisposeOf; // TComponent Free Notification mechanism notifies registered components that particular
// component instance is being freed. Notified components can handle that notification inside
// virtual Notification method and make sure that they clear all references they may hold on
// component being destroyed.
//
// Free Notification mechanism is being triggered in TComponent destructor and without DisposeOf
// and direct execution of destructor, two components could hold strong references to each
// other keeping themselves alive during whole application lifetime.
{$IF defined(DEBUG)}
if (Temp.RefCount - 1) and (not $40000000{Temp.objDisposedFlag}) <> 0 then
ALLog('ALFreeAndNil', Temp.ClassName + ' | Refcount is not null (' + Inttostr((Temp.RefCount - 1) and (not $40000000{Temp.objDisposedFlag})) + ')', TalLogType.warn);
{$IFEND}
temp := nil;
end;
{$ELSE}
temp.Free;
temp := nil;
{$IFEND}
end;
这样,如果调用ALFreeAndNil后refcount不为0,那么它会在日志中产生警告(正在调试中),您可以调查