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.

1
  • See here. PS: You don't need the www parameter at all Commented 5 hours ago

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.