Вызов объективного блока кода C из delphi

Я пытаюсь заставить работать фоновую загрузку в моем приложении firemonkey.

Я дошел до того, что мой perfromFetchWithCompletionHandler вызывается и загружает новую информацию.

Проблема возникает, когда я заканчиваю выборку и мне нужно вызвать блок кода завершений, приложение зависает, и я не получаю никаких исключений (которые я, по крайней мере, могу прочитать)

Настроить:

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;

Справочная страница executeFetchWithCompletionHandler

Я пробовал с разными объявлениями типа указателя на функцию, но так как это не указатель на функцию, я думаю, поэтому она не будет работать.

Есть идеи?

Спасибо роберт

2 ответа

Решение

Я нашел решение, которое работает: imp_implementationWithBlock

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

// Изменен обработчик на тип id (указатель)

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';

// Добавлены ссылки на imp_implementationWithBlock и imp_removeBlock из libobjc

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

// Объявлен тип IMP как переменная функция, соответствующая указателю на функцию, возвращаемому 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;

Это то, что Apple называет " блоками".

Вы можете найти более подробную техническую информацию о них в следующем документе Apple: http://www.opensource.apple.com/source/libclosure/libclosure-53/BlockImplementation.txt

К сожалению, это не так просто реализовать в Delphi. Поэтому может быть лучше создать dylib target-c, который, в свою очередь, позаботится о блоке и будет использовать его из вашего приложения Delphi.

Другие вопросы по тегам