【问题标题】:Calling objective C code block from delphi从delphi调用目标C代码块
【发布时间】:2014-04-17 10:26:20
【问题描述】:

我正在尝试在我的 firemonkey 应用程序中进行后台提取工作。

到目前为止,我的 perfromFetchWithCompletionHandler 被调用并下载新信息。

当我完成 fetch 并需要调用 completionHandler 代码块时,问题就出现了,应用程序挂起并且我没有收到任何异常(至少我可以读取)

设置:

TBackgroundFetchResultHandlerC = procedure ( AResult : NSUInteger ); cdecl;
.. 
..

procedure performFetchWithCompletionHandler(self : id; _cmd : SEL; application: PUIApplication; handler : TBackgroundFetchResultHandlerC );
..
..

objc_msgSend((UIApp as ILocalObject).GetObjectId,
             sel_getUid('setMinimumBackgroundFetchInterval:'),
             Interval);
class_addMethod( objc_getClass('DelphiAppDelegate') ,
                sel_getUid('application:performFetchWithCompletionHandler:'),
                @performFetchWithCompletionHandler,
                'v@:@?'
  );
..
..

procedure performFetchWithCompletionHandler(self : id; _cmd : SEL; application:         PUIApplication; handler : TBackgroundFetchResultHandlerC );
var t : TThread;
begin
  NSLog3('performFetchWithCompletionHandler:begin');
  Handler(0); <<--Stops here
  //Next line of code never gets called.
  NSLog3(Format('performFetchWithCompletionHandler:done, done',[ FetchResult ]) );
end;

performFetchWithCompletionHandler man page

我尝试过使用不同的函数指针类型声明,但由于它不是函数指针,我想这就是它不起作用的原因。

有什么想法吗?

谢谢 罗伯特

【问题讨论】:

  • 你知道source\rtl\osx\Macapi.OCBlocks.pas 文件吗?
  • 不,我不知道。我去看看,谢谢!

标签: ios delphi objective-c-blocks firemonkey


【解决方案1】:

我找到了一个可行的解决方案:imp_implementationWithBlock

procedure performFetchWithCompletionHandler(self : id; _cmd : SEL; application:    PUIApplication; handler : id );

//把handler改成类型id(Pointer)

const
  libobjc = '/usr/lib/libobjc.dylib';

{$IF NOT DECLARED(_PU)}
  const
  {$IFDEF UNDERSCOREIMPORTNAME}
    _PU = '_';
  {$ELSE}
    _PU = '';  
  {$ENDIF}
  {$EXTERNALSYM _PU}
{$ENDIF}

function imp_implementationWithBlock( block :id ) : IMP; cdecl; external libobjc name  _PU + 'imp_implementationWithBlock';
function imp_removeBlock( anImp : IMP ) : integer; cdecl; external libobjc name _PU + 'imp_removeBlock';

//添加了对libobjc中imp_implementationWithBlock和imp_removeBlock的引用

type  IMP = function( self : id; cmd : SEL; Param1 : NSUInteger ) : id; cdecl;

//将IMP类型声明为一个c函数,对应于在这种特殊情况下imp_implementationWithBlock返回的函数指针,带有一个NSUInteger参数。

procedure performFetchWithCompletionHandler(self : id; _cmd : SEL; application: PUIApplication; handler : id );
var
  ahandlerimp : IMP;
begin
   .... //Code to perform fetch 
  ahandlerimp := imp_implementationWithBlock( handler ); //Create c function for block
  ahandlerimp(self,_cmd,FetchResult ); //Call c function, _cmd is ignored
  imp_removeBlock(ahandlerimp); //Remove the c function created two lines up
end;

【讨论】:

  • 我想知道这种技术是否适用于 ALAssetsLibrary 中的 enumerateGroupsWithTypes?我一直在为这个问题挠头。在此期间我会继续抓挠..
  • 这里FetchResult的值是多少? ahandlerimp 函数是否使用了它?因为我不能让它工作:(
  • performFetchWithCompletionHandler 应该被 iOS 调用。然后,在我的实现中( .... //上面执行 fetch 的代码)我将“全局”变量 Fetching 设置为 1。启动 fetching 线程。等待 Fetching 变为 1 以外的值。FetchResult 由线程在终止事件时设置为 0(newData)、1(无 Data)或 2(失败)以及 Fetching = 0。
【解决方案2】:

这就是 Apple 所说的“blocks”。

您可以在以下 Apple 文档中找到有关它们的更多技术细节: http://www.opensource.apple.com/source/libclosure/libclosure-53/BlockImplementation.txt

不幸的是,从 Delphi 实现这一点似乎并不容易。因此,创建一个objective-c dylib 可能是更好的选择,它会依次处理该块并在您的Delphi 应用程序中使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-10
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多