Проблема в том, что ваш код не сохраняет интерфейс 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
.Последний вариант имеет гораздо лучшую инкапсуляцию.