Вызов объективного блока кода 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.