I have been trying to create a function that can return a list and the
list can be used on a user interface. The function is working but
despite freeing all the objects the application is leaking memory.
//Function for returning list
function TDBRepository.GetUserList: TList<TUser>;
begin
DBManager := TObjectManager.Create(DBConnection);
Result := DBManager.FindAll<TUser>;
DBManager.OwnsObjects := False;
DBManager.Free;
end;
//User Interface side
procedure TFrm_CSUsers.LoadList;
var
MyUserList : TList<TUser>;
begin
MyUserList := DBRepository.GetUserList;
MyUserList.Free;
end;
What might I be doing wrong?
Do not set DBManager.OwnObjects to false. The list returned by FindAll does not owns its objects so you have to manually destroy the list itself, but the objects contained by the list are destroyed by the manager.
But the OP is setting the manager owns objects to false and freeing the manager after the list is filled. If he really wants to control the objects outside of the manager, he should use a TObjectList instead of a TList, and set the list OwnsObjects property to true.
White Dave's suggestion worked and here is the change made
//Ammended function
function TDBRepo.GetUserList: TObjectList<TUser>;
var
TempResult : TObjectList<TUser>;
begin
DBManager := TObjectManager.Create(DBConnection);
TempResult := DBManager.FindAll<TUser>;
Result := TempResult;
TempResult.OwnsObjects := True;
DBManager.OwnsObjects := False;
DBManager.Free;
end;
The better way is just to keep the manager alive while using the objects created by it. Don't destroy the manager. This approach might work with entities that don't have associations, but once you have associations in them (like a list of TCustomer objects that point to TCountry objects through a Country property), you will have memory leaks again.