Ответ 1
Проблема заключается в том, что ваш код не сохраняет интерфейс IAsyncCall
, который возвращается функцией AsyncCall
.
AsyncCall(@Load, []);
//AsyncCall returns an IAsyncCall interface,
//but this code does not take a reference to it
Из-за этого возвращаемый интерфейс имеет счетчик ссылок, уменьшенный до нуля, как только завершается раздел инициализации. Поэтому это освобождает объект, который реализует интерфейс, который делает это:
destructor TAsyncCall.Destroy;
begin
if FCall <> nil then
begin
try
--> FCall.Sync; // throw raised exceptions here
finally
FCall.Free;
end;
end;
inherited Destroy;
end;
Ключевой линией является вызов Sync
, который заставляет выполнить асинхронный вызов для завершения. Все это происходит в основном потоке, который объясняет поведение, о котором вы сообщаете.
Решение состоит в том, что вам просто нужно поддерживать интерфейс IAsyncCall
, сохраняя его в переменной.
var
a: IAsyncCall;
initialization
a := AsyncCall(@Load, []);
В реальном коде вам нужно убедиться, что Load
был завершен до запуска любого кода, который зависит от Load
. Когда ваша программа достигла точки, в которой требовалось Load
для вызова, она должна вызвать Sync
в интерфейсе IAsyncCall
.
Итак, вы можете написать что-то вроде этого.
unit MyUnit;
interface
procedure EnsureLoaded;
implementation
uses
AsyncCalls;
....
procedure Load;
begin
....
end;
var
LoadAsyncCall: IAsyncCall;
procedure EnsureLoaded;
begin
LoadAsyncCall := nil;//this will effect a call to Sync
end;
initialization
LoadAsyncCall := AsyncCall(@Load, []);
end.
Вызов EnsureLoaded
из других единиц, для выполнения которого требуется Load
. Или, альтернативно, вызовите EnsureLoaded
из любых методов, экспортированных с помощью MyUnit
, которые зависели от запуска Load
. Последний вариант имеет гораздо лучшую инкапсуляцию.