The reference count ARC is something very confusing under delphi, and it's make development much more harder that it's must be because it is badly designed (under delphi).
First it's build in RTL, and it's quite similar to what you have with String. it's work on plateform (firemonkey) and also on OS (work only on android/ios/unix). So if you want to build multi plateform code that target also window (most probable, a least just to debug you code) you will anyway need to keep the try ... finally .. end; (yes i say you, very bad design). so forget about your example without .free except if you want to debug under mobile (and good luck with 3 min compilation everytime, it's simply not possible)
NOTE: To keep you code compatible as most as possible a good rule to acquire is to replace all you .free by .disposeOF followed by nil because under mobile, free is a no-ops operation and you object is not destroyed, and can be destroyed at a very unexpected time (or simply never be destroyed in worst case, quite common if you use for example TTask). these scenarios are not so rare, especially if you use often anonymous procedure (reference to procedure) that create in the background capture to your object.
Always keep in mind that circular ref are quite easy to meet and quite
hard to detect
.
after you must know also (you didn't ask, but i extend a little the answer) that their is delphi Tobject, java object, IOS objective C object and Interface. All have their own rules and confuse everyone and at the end no-one really know how it's work (yes part of the badly design of ARC is also the confusion it's gave), even emb developer do mistake in their delphi source code, look for exemple this question: delphi + ios: release / retain and reference counting with objective-c object that is quite trivial, but without any answer
ARC and Objective-C wrapped objects
Delphi NextGen compiler implements automatic reference counting (ARC) for all Delphi objects. The compiler will manage the logic to TObject’s __ObjAddRef and __ObjRelease for you. Objective-C code uses the same logic to call retain and release. Unfortunately there is no ARC for the Objective-C objects represented by the import wrapper class and the interfaces discussed above. When dealing with Objective-C objects you’ll have to call retain and release yourself at the correct points.
ARC and JAVA object
On the paper it's must work, but personally i don't trust it, for exemple if you do in loop :
for i := 0 to 100000 do begin
aJstring := StringToJstring('a text');
aStr := JstringToString(aJstring);
end;
normally this must run without any trouble in a normal world, but under delphi, it's will crash :( but anyway here you don't have .release so you don't have choice (except assigning the variable to nil). But when you have choice this why i recommend always to use .disposeOF followed by nil, you will probably win days/weeks/month of development escaping some nasty bug.
NOTE: i call this function when i want to destroy an object:
{******************************}
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;
In this way, if the refcount is not 0 after calling ALFreeAndNil, then it's generate a warning in the log (under debug) and you can investigate