ios – Can I safely emulate callback-like behaviour in Task.Run by calling the desired target procedure from TThread.Synchronize?

0
204


I am successfully using Delphi’s TRESTRequest.ExecuteAsync to query a REST API and parse the results without blocking the main thread.

This is for a mobile app with devices moving in and out of coverage, so I want to check that the server is reachable immediately prior to making the call. I tried using TRESTClient’s timeout, but it takes 30 seconds to fire, even when Airplane mode is turned on.

I have a very quick and reliable function CheckServerIsAvailable, but it is synchronous. To avoid blocking the main thread, I call CheckServerIsAvailable via Task.Run, and using TThread.Synchronize to update my UI when it’s done. This seems to work reliably.

However, I want the application to continue from that point and either show a message that the server is unavailable OR continue into making the call to the server. I don’t want to put all the additional error checking and JSON parsing etc code inside the Thread.Synchronize procedure declaration as it will quickly become unreadable.

Thread.Synchronize docs says the anonymous procedure is called on the main thread, so I tried to continue the execution by calling another procedure from there as follows:

procedure TForm1.Button1Click(Sender: TObject);
begin
StartWithPart1;
end;

procedure TForm1.StartWithPart1;
begin
Label1.Text := 'Looking...';
AniIndicator1.Enabled := true;
TTask.Run(
  procedure
  begin
  Connected := CheckServerIsReachable;  // this is a blocking call
  TThread.Synchronize(nil,
    procedure
    begin
    Label1.Text := ifthen(Connected, 'Connected', 'Not connected');
    AniIndicator1.Enabled := false;
    ShowMessage('leaving part 1');
    ContinueWithPart2;
    end);
  end);
end;

procedure TForm1.ContinueWithPart2;
begin
ShowMessage('entering part 2');
// this is where I want to make the REST call, handle errors and parse results etc
end;

This seems to work correctly, with the TAniIndicator animating and labels updating correctly, but when I run the code above, the message “entering part 2” appears before “leaving part 1”, which makes me think that my (limited) understanding of TThread.Synchronize is either incorrect or incomplete or both.

Is this approach reasonable? Why does the second message appear before the first if TThread.Synchronize is executing on the main thread? Is there a better model to be using to achieve what I’m trying to do?