I’m trying to implement this iOS delegate method in Delphi:
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task willBeginDelayedRequest:(NSURLRequest *)request completionHandler:(void (NS_SWIFT_SENDABLE ^)(NSURLSessionDelayedRequestDisposition disposition,
NSURLRequest * _Nullable newRequest))completionHandler API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0));
My Delphi translation looks like this:
procedure TURLSessionDelegate.URLSession(session: NSURLSession;
task: NSURLSessionTask;
willBeginDelayedRequest: NSURLRequest;
completionHandler: Pointer);
var
LCompletionHandlerBlock: procedure(disposition: NSURLSessionDelayedRequestDisposition;
newRequest: NSURLRequest); cdecl;
begin
@LCompletionHandlerBlock := imp_implementationWithBlock(completionHandler);
try
LCompletionHandlerBlock(NSURLSessionDelayedRequestCancel, nil);
finally
imp_removeBlock(@LCompletionHandlerBlock);
end;
end;
the problem: it crashes on the call
LCompletionHandlerBlock(NSURLSessionDelayedRequestCancel, nil);
However, this version seems to work:
procedure TALHttpWorker.TURLSessionDelegate.URLSession(session: NSURLSession;
task: NSURLSessionTask;
willBeginDelayedRequest: NSURLRequest;
completionHandler: Pointer);
var
LCompletionHandlerBlock: procedure(disposition: NSURLSessionDelayedRequestDisposition;
zzz: Pointer;
newRequest: Pointer;
www: Pointer); cdecl;
begin
@LCompletionHandlerBlock := imp_implementationWithBlock(completionHandler);
try
LCompletionHandlerBlock(NSURLSessionDelayedRequestUseNewRequest,
nil,
NSObjectToID(willBeginDelayedRequest),
nil);
finally
imp_removeBlock(@LCompletionHandlerBlock);
end;
end;
If I declare the block as procedure(disposition: NSURLSessionDelayedRequestDisposition; newRequest: NSURLRequest); cdecl; → it crashes when invoked.
If I declare it as procedure(disposition: NSURLSessionDelayedRequestDisposition; zzz: Pointer; newRequest: Pointer; www: Pointer); cdecl; and pass dummy nil values for zzz and www → it works, and disposition / newRequest are correctly taken into account.
I don’t understand why I need those two extra dummy parameters to make it work. The original Objective-C block signature only has two parameters:
void (^)(NSURLSessionDelayedRequestDisposition disposition,
NSURLRequest * _Nullable newRequest)
- Why does the “natural” Delphi translation with only two parameters crash?
- Why does adding two extra Pointer parameters (zzz / www) suddenly make it work?
- What is the correct Delphi declaration for this completionHandler block when using imp_implementationWithBlock?
Any explanation about the calling convention / block ABI here (and how to properly map it in Delphi) would be very helpful.