0

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.

5
  • See here. PS: You don't need the www parameter at all Commented Nov 22 at 3:18
  • @DaveNottage You’re right, I can remove the www parameter and it still works, but I still don’t understand why the zzz parameter has to be in the middle, between disposition and newRequest. From the docs you sent, it looks like it should be in the first position, no? Also, why do all the Delphi code samples I see that use imp_implementationWithBlock not use any extra parameters and still work as expected? Commented Nov 22 at 11:44
  • @DaveNottage when i say : "Also, why do all the Delphi code samples I see that use imp_implementationWithBlock not use any extra parameters and still work as expected?" it's also the same for Kastri, you do not use any dummy parameters Commented Nov 22 at 12:44
  • "it's also the same for Kastri, you do not use any dummy parameters". Because all the blocks have either no parameters or one parameter, so there's no need for a dummy second parameter. There's at least one example of a dummy parameter in the RTL in System.Net.HttpClient.Mac. See the TMacConnectionDataDelegate.URLSessionTaskDidReceiveChallengeCompletionHandler method. Commented Nov 22 at 19:40
  • @DaveNottage You're right, my mistake, I didn’t notice it. In URLSessionTaskDidReceiveChallengeCompletionHandler it’s exactly the same problem :( So I’ll go ahead and use a dummy parameter, I just wish I understood why this dummy parameter is required. Commented Nov 22 at 22:45

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.