为什么有些ios标题被转换为没有cdecl的pascal?

时间:2017-04-27 07:46:55

标签: ios objective-c delphi

当我看一些ios标题如何被翻译成delphi时,我可以看到例如

typedef void(^FIRMessagingConnectCompletion)(NSError * __nullable error);

已翻译:

FIRMessagingConnectCompletion = procedure(error: NSError) of object;

然而我不明白为什么不用 cdecl ; ?因为ios中的所有内容都必须使用cdecl;为什么它没有被翻译成:

FIRMessagingConnectCompletion = procedure(error: NSError) of object; cdecl;

注意/修改

要回答Remy和Rudy,让一切都清楚,我想从一个原始的Delphi源代码中找出一个问题的好例子

在delphi中我们声明了这个接口:

  NSURLSessionTaskDelegate = interface(IObjectiveC)
    ['{C48E0AED-64F3-45A4-8D42-E3DB12F668E7}']

    procedure URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler(session: NSURLSession;
      task: NSURLSessionTask; willPerformHTTPRedirection: NSHTTPURLResponse; newRequest: NSURLRequest;
      completionHandler: TFoundationCompletionHandler7); cdecl;

  end;

type
  TFoundationCompletionHandler7 = procedure(param1: NSURLRequest) of object;

所以我决定像这样实现它:

  TMyNSURLSessionTaskDelegate = class(TOCLocal, NSURLSessionTaskDelegate)
  public

    procedure URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler(session: NSURLSession;
      task: NSURLSessionTask; willPerformHTTPRedirection: NSHTTPURLResponse; newRequest: NSURLRequest;
      completionHandler: TFoundationCompletionHandler7); cdecl; 

  end;

但是(你可以尝试自己)只要你做TMyNSURLSessionTaskDelegate.create就会收到错误TFoundationCompletionHandler7 = procedure(param1: NSURLRequest) of object; is not a valid ObjectiveC type

问题出在哪里?如何使用NSURLSessionTaskDelegate?

2 个答案:

答案 0 :(得分:1)

您为Delphi的NSURLSessionTaskDelegate接口显示的声明与Apple's declaration of URLSessionTaskDelegate不匹配,因此不能在Objective-C中按原样使用。这就是编译器所抱怨的。

NSURLSessionTaskDelegate参数使用的完成处理程序的类型应该更像这样:

TFoundationCompletionHandler6 = procedure(param1: NSURLSessionAuthChallengeDisposition; param2: NSURLCredential); cdecl;
TFoundationCompletionHandler7 = procedure(request: NSURLRequest); cdecl;
TFoundationNeedNewBodyStream = procedure(param1: NSInputStream); cdecl;

of object替换为cdecl

在转换iOS标题时,这显然是Embarcadero的一个错误(坦率地说,我很惊讶它通过测试而没有被发现)。

然后,您将实现您的委托类:

type
  TMyUrlSessionHTTPRedirection = procedure(
    session: NSURLSession; task: NSURLSessionTask;
    willPerformHTTPRedirection: NSHTTPURLResponse;
    var newRequest: NSURLRequest) of object;

  TMyNSURLSessionTaskDelegate = class(TOCLocal, NSURLSessionTaskDelegate)
  public
    OnHttpRedirection: TMyUrlSessionHTTPRedirection;
    ...
    procedure URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler(
      session: NSURLSession; task: NSURLSessionTask;
      willPerformHTTPRedirection: NSHTTPURLResponse; newRequest: NSURLRequest;
      completionHandler: TFoundationCompletionHandler7); cdecl;
    ...
  end;

procedure TMyNSURLSessionTaskDelegate.URLSessionTaskWillPerformHTTPRedirectionNewRequestCompletionHandler(
  session: NSURLSession; task: NSURLSessionTask;
  willPerformHTTPRedirection: NSHTTPURLResponse; newRequest: NSURLRequest;
  completionHandler: TFoundationCompletionHandler7); cdecl;
var
  finalRequest: NSURLRequest;
begin
  finalRequest := newRequest;

  if Assigned(OnHttpRedirection) then
    OnHttpRedirection(session, task, willPerformHTTPRedirection, finalRequest);

  completionHandler(finalRequest);
end;

然后,您将创建TMyNSURLSessionTaskDelegate的实例,并为OnHttpRedirection成员分配Delphi对象方法,然后将委托实例传递给iOS。在适当的时候,它会调用委托的urlSession()方法,该方法将调用OnHttpRedirection处理程序。

在Embarcadero修复他们的错误之前,您必须使用正确的类型声明在您自己的代码中重新声明NSURLSessionTaskDelegate接口。

答案 1 :(得分:0)

它的工作原理如下:

  • Delphi包装器公开iOS对象的方法
  • 这些不是直接调用的。每次调用包装器的方法都会使包装器使用适当的参数调用iOS对象的相应方法。
  • iOS对象调用回调函数,该回调函数由包装器拦截。这使得包装器调用{strong> Delphi版本 FIRMessagingConnectCompletion方法(没有cdecl的方法)。 Delphi方法中的代码完全在Delphi中,并在Delphi上下文中运行。最初的iOS对象永远不会看到它,也不需要。
  • 该方法可以在Delphi中完全实现,并由Delphi对象调用。它很可能是表格的一种方法。这就是为什么它被声明为of object,就像一个事件,并且没有被声明为cdecl,因为它完全在Delphi环境中运行。

声明与原始声明非常相似,使其看起来好像正在实现回调,但实际上您正在实现Delphi事件。这样可以更轻松地翻译iOS示例和其他iOS代码,尽管底层类型/代码和基础结构完全不同。