ApplyStyle and FreeStyle in FireMonkey

If you’re writing custom controls for FireMonkey you’re probably overriding ApplyStyle with something like this:

procedure TWidget.ApplyStyle;
var 
TTFMXObject;
begin
    inherited
;
    
:= FindStyleResource('text');
    if 
T is TText then
        FText 
:= TText(T);
end

And so you should be. That’s entirely correct practice. You look for a component of the style and cache it for later re-use within your component.

procedure TWidget.SetText(const ValueString);
begin
    
if FText <> nil then
        FText
.Text := Value;
end

But as I was updating MonkeyStyler to run under XE3/FM2 I was getting some really obscure errors from my custom grid cells. The cached components would occasionally be junk, as though they had been free-ed behind my back. The errors always occured in the final cell in a row and I at first assumed there was some really odd off by one bug in FM2.

After much investigation I noticed that ApplyStyle was being called on cells which had long been created. But why would ApplyStyle be called more than once on a component?

It turns out that FM2 is being more conservative with resources and freeing style objects which are no longer needed to save memory. If a component disappears from view the library will call TStyleControl.Disappear which in turn calls the virtual TStyleControl.FreeStyle. I’ll admit I had’t even noticed these methods before.

The correct behaviour for any component which caches style resources in it’s ApplyStyle method is, therefore, to override FreeStyle and release them:

procedure TWidget.FreeStyle;
begin
    inherited
;
    
FText := nil;
end

Once I added that to MonkeyStyler’s custom cells all ran smoothly again.

Enjoy.

Commenting is not available in this channel entry.