Sự cố là mã của bạn không giữ lại giao diện IAsyncCall
được trả về bởi hàm AsyncCall
.
AsyncCall(@Load, []);
//AsyncCall returns an IAsyncCall interface,
//but this code does not take a reference to it
Do đó, giao diện được trả lại có số tham chiếu được giảm xuống 0 ngay khi phần khởi tạo hoàn tất. Điều này do đó giải phóng các đối tượng mà thực hiện các giao diện mà thực hiện điều này:
destructor TAsyncCall.Destroy;
begin
if FCall <> nil then
begin
try
--> FCall.Sync; // throw raised exceptions here
finally
FCall.Free;
end;
end;
inherited Destroy;
end;
Điểm mấu chốt là cuộc gọi đến Sync
mà lực lượng các cuộc gọi không đồng bộ được thực hiện để hoàn thành. Tất cả điều này xảy ra trong chuỗi chính giải thích hành vi mà bạn báo cáo.
Giải pháp là bạn chỉ cần giữ giao diện IAsyncCall
còn sống bằng cách lưu trữ nó trong một biến.
var
a: IAsyncCall;
initialization
a := AsyncCall(@Load, []);
Trong mã thực bạn cần phải đảm bảo rằng Load
đã hoàn thành trước khi chạy bất kỳ mã đó là phụ thuộc vào Load
. Khi chương trình của bạn đạt đến một điểm mà nó yêu cầu Load
để được gọi thì phải gọi Sync
trên giao diện IAsyncCall
.
Vì vậy, bạn có thể viết nó như thế này.
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.
Gọi EnsureLoaded
từ các đơn vị khác yêu cầu Load
để chạy. Hoặc, cách khác, hãy gọi EnsureLoaded
từ bất kỳ phương thức nào được xuất bởi MyUnit
phụ thuộc vào Load
khi chạy. Tùy chọn thứ hai có đóng gói tốt hơn nhiều.
Nguồn
2012-01-10 20:11:00
Không. Không hoạt động.Ngay cả khi tôi đặt nó ra khỏi khởi tạo nhưng tải thủ tục trên một số nút giả. –