I'm trying to make background fetch work in my firemonkey application.

I've gotten so far that my perfromFetchWithCompletionHandler gets called and downloads new information.

The problem comes when I'm done with my fetch and need to call the completionHandler code block, the app hangs and I don't get any exception (that I can read at least)

Setup:

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

I've tried with different declarations of the function pointer type, but as it isn't a function pointer exactly I guess that's why it won't work.

Any ideas?

Thanks Robert

有帮助吗?

解决方案

I've found a solution that works: imp_implementationWithBlock

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

//Changed the handler to type 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';

//Added references to imp_implementationWithBlock and imp_removeBlock from libobjc

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

//Declared type IMP as a c function corresponding to the function pointer returned by imp_implementationWithBlock in this particular case with one NSUInteger parameter.

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;

其他提示

This is what Apple calls "blocks".

You can find a bit more technical detail about them in the following document from Apple: http://www.opensource.apple.com/source/libclosure/libclosure-53/BlockImplementation.txt

Unfortunately it doesn't appear to be easy to implement that from Delphi. So it might be a better choice to create an objective-c dylib that will in turn take care of the block and use that from your Delphi application.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top