In Delphi, we will often create an object, use it, then destroyed it. All object in Delphi need to be destroyed in order to prevent memory leaked (a condition where the object still occupy a block of memory even when the application already terminated, thus making the object don’t have an owner to destroy it). On a simple project where we just use objects that we put on the form at design time (a term to tell a time where we design our form before the application is run), the objects is owned by the form, thus it will automatically destroyed when the form destroyed, so we don’t have to think about the memory leaked.
This behaviour is making development much easier, we don’t have to manage the objects lifecycle ourself, but this condition is not suitable for a much bigger projects where we need to use a lot more forms and other objects that if we make them automatically created and destroyed by Delphi will make our program consume a lot of memory that wasted the resources as not all of the forms and objects needs to be created at first run, they should be run or created when needed. This is what we call as “Created at run time”.
When we create object at run time, we must make sure the object gets destroyed when the application terminated. Luckily, Delphi can help us handle most of runtime object destruction, in Delphi if we create an object descended from a TComponent, i has an owner parameter. This parameter is important, it defines who the owner of the object, and then this owner will be responsible to destroy all the objects it owned.
There are few type of owner we can assigned to an object we create, they are:
- A Component, an object that descended from TComponent
- Application object, an object that owns the application
- Nil, no object owned them
When we assigned an object to a component, then when that component destroyed, the object also gets destroyed. When we assigned an object to an application object, then that object gets destroyed only when application terminated. When we assigned nil to the owner of the object, we really need to handle the destruction of the object ourself, it won’t gets destroyed even if the application terminated.
So it should be easy right, just set the owner of all the object to a component or application object, it will be solved automagically by Delphi, well, not quite true nor false, it depends on what we need with that object we created. If we need an object that will be used as long as the object’s owner alive, then you can use that method. But when we need to recreate the object many times while the object’s owner still alive, then we can’t use the method. For example, we want a button in a form create another form as a dialog form to do something, and it is possible to click many times on that same button with the same routine that will show a dialog form, then we will face a problem with the dialog form lifecycle.
Everytime we create an object, it will consume a block of memory until we destroyed the object, so even though we assigned an owner of the object to the form, then as long as the form hasn’t destroyed, then all the objects we create will stay alive and stay at the memory, and if we just creates the object every time we press that button, then it will create a lot of objects and consume more memory block, then finally we will face an out of memory problem if we have a lot of object that created this way.
So what is the solutions? There are few ways to solve this problems, I will only discuss one of them. Yes, like the title of this blog said, to check the object reference before we create a new object. So most of the time, we better to always check an object reference before we create another object (I will discuss later about why I mention most of the time, it really means not all the time 😊). To check for an object reference, there are several ways to do it.
We can use the Assigned method where it takes a pointer as the parameter. The pointer should be an address (in memory) of the object we want to check. This method will check whether the address specified in the parameter still point to a valid object’s reference address, but it is important to know and remember that it will only check whether the address specified is assigned to an object’s reference adress or unassigned (nil). So even if we check the variable that stored the object’s reference address with assigned method, we still can’t make sure whether the object already destroyed or not.
We can also use a direct comparison of an object with nil, the result is the same with Assigned method before. The syntax is like this:
if MyObject <> nil then
Well this looks like a much better way to check an object reference, so why is there Assigned method? Assigned method is a method to check a valid pointer, so it can also check for a valid procedural variable without executing the procedure.
So if a direct comparison for an object with nil can do the job well, do we still need assigned method to check of an object reference? Assigned method actually doing the same thing like the code above for an object reference, it just that it can also check for a valid procedural variable correctly, so in my opinion, we better use assigned method for all object reference checking, this will make it easier to remember and for uniformity of our code.
There is still something very important we need to discuss, it is true that we just need to check for the object reference whether it still a valid object or not, but how to make sure an object already destroyed and the reference address already unassigned (nil)? To destroy an object, we use Free method, but this method will only free the reference object, not the reference address, the reference address will still hold the object’s reference address, thus when we check using assigned method or compare it with nil directly, it will still return a valid object’s reference address but not a valid object. So to make it correctly destroy the object and object’s reference address we need to set the reference address to nil. So it will looks like this:
MyObject.Free;
MyObject := nil;
That code will make sure that MyObject will no longer hold the object and the object’s reference address and this code snippet will work correctly and safely:
if not Assigned(MyObject) then
begin
MyObject := TForm1.Create(self);
end;
A complete simple object creation snippet will look like this one:
if not Assigned(MyObject) then
begin
MyObject := TForm1.Create(self);
try
MyObject.ShowModal;
finally
MyObject.Free;
MyObject := nil;
end;
end;
In that code sample, you need to make sure to use ShowModal, so the form won’t get destroyed after it is created.
There is actually a method provided by Delphi to make it easier to destroy an object correctly, that is the FreeAndNil method, it basically do the same thing as the code I mention above, that is to free and set nil to the reference address.
So, why not always use FreeAndNil to all objects we create, well this is the part to discuss where I mention before that I use “most of the time” to check for an object reference. As the project goes bigger and bigger, you might face a condition where you can’t or you don’t want to control the variable that store the object’s reference address. Then with this condition, you can only destroy the object, but you can’t set the object’s reference address to nil, so you can’t use the object reference checking method to make sure you create the object only once and will not consume more memory.
Then what can we do when we face this kind of condition? Actually there is no way to check without knowing the reference address that stored somehow, but in my case, there is a solutions. In my case I face the problem for forms object, where I don’t want to maintain the variable that store the form object’s reference address. In Delphi, all created forms’ reference address will also stored in the TScreen object, it is in the Screen.Forms property to be exact. This property hold all forms object that created at design time or at run time. So we just need to check whether our form that we want to recreate is exists in the Screen.Forms list.
With this method, we just need to assigned an event on the Form’s OnClose event to set the Action to caFree, so when the form closed, the form’s object will be destroyed automagically, and we don’t have to check the form’s reference address using Assigned method or direct comparison to nil method. Here is the code snippet to check for the form instance before we recreate it:
function IsFormLoaded(AFormName : string) : boolean;
begin
Result := False;
for var i := 0 to Screen.FormCount - 1 do
begin
if CompareText(Screen.Forms[i].Name, AFormName) then
begin
Result := True;
break;
end;
end;
end;
So the answer to the question “Do We Need to Check Object Reference”, it’s definitely a yes and in my opinion, you always need to make this method as your coding habit to make less bug in the future.
That’s all I need to say this time, if you have any question or want to discuss more, feel free to comment. There will be a webinar “FreeAndNil() – Delphi Developer Debate” by Embarcadero, don’t missed it and make sure you register it here : https://blogs.embarcadero.com/freeandnil-delphi-developer-debate/
Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder.
Design. Code. Compile. Deploy to Windows, Linux, macOS, iOS, and Android. There is a great discount promo until June 30, 2022, please visit our store and you can order directly here: https://www.interaktif.solutions/product-category/embarcadero/
Iwan CS