Question

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

Was it helpful?

Solution

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;

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top