Using these destroyed instances after they have been disposed of might result in an error, but that's not much different than circumstances under the classic Delphi compilers, where freeing an instance and using other references to it results in an error. What is significantly different is that under the classic Delphi compilers, when you have two references to an object and free the object using one of them, there is no way to know if the other reference is still valid. Instead, using
DisposeOf, you can query an object about its status:
myObj := TMyClass.Create; // an object reference myObj.SomeData := 10; myObj2 := myObj; // another reference to the same object myobj.DisposeOf; // force cleanup if myobj2.Disposed then // check statusof other reference Button1.Text := 'disposed';
As I mentioned earlier, the
try-finally blocks used on the classic Delphi compilers still work fine under the new compiler, even if they are not required. In specific cases in which you want to force the execution of the destructor code as soon as possible and regardless of other references, you might want to use the dispose pattern instead:
var MyObj: TMySimpleClass; begin MyObj := TMySimpleClass.Create; try MyObj.DoSomething; finally MyObj.DisposeOf; end; end;
In the classic compilers, the effect remains the same, as
Free. With ARC, however, the code executes the destructor when expected (that is, at the same time as with the classic compiler), but the memory is managed by the ARC mechanism. This is handy, but you cannot use this same code for compatibility with older versions of Delphi. For that purpose, you might want to call
FreeAndNil, redefining this procedure as a call to either
DisposeOf. You can also just stick with a standard call to
Free, which does the trick most of the time.
One way to look at the difference between
DisposeOf is to consider the intent of the two operations under ARC (as opposed to what happens under classic Delphi compilers). When using
Free, the intent is that the specific reference should simply detach from the instance. It does not imply any kind of disposal or memory deallocation. It's merely that a specific block of code doesn't need that reference anymore. Usually, this will happen automatically upon exiting the scope, but you can force it by calling
DisposeOf is the programmer's way of explicitly telling the instance that it needs to clean itself up.
DisposeOf never necessarily implies memory deallocation; it merely does an explicit clean up of the instance (executing any specific destructor code). The instance still relies on the normal reference count semantics to eventually deallocate the memory it uses.
Free is an "instance reference-centric" operation, whereas
DisposeOf is an "instance-centric" operation.
Free means, "I don't care what happens to the instance, I just don't need it anymore."
DisposeOf means, "I need this instance to internally clean itself up since it may be holding a non-memory resource that needs to be released (such as a file handle, database handle, a socket, and so on)".
We are particularly pleased with this approach because it not only delivers ARC on mobile, but maintains code compatibility on desktop operating systems. Ultimately, our goal is to bring ARC across all platforms, but this new language feature really shines on mobile.
This is very exciting time to be a Delphi developer. Not only can iOS on ARM be targeted now, but Android is coming soon. And just like the code compatibility we've accomplished with ARC, the code between iOS and Android (and Windows and Mac OS X) will be fully compatible so developers can deliver apps on all of these operating systems and associated devices with a single, natively compiled source code base.
John Ray Thomas is the Director of Project Management, Marco Cantu is the Delphi Product Manager, and Allen Bauer is Chief Scientist at Embarcadero.