У вас есть несколько вариантов.
Использование блоков
Вы можете использовать блоки для передачи вашей работы обратного вызова. Это, вероятно, самое простое решение, поскольку оно позволяет вам вызывать ваш код без необходимости передавать какой-либо параметр в «функцию» обратного вызова. Блоки работают в C и во всех его надмножествах с Clang, а Clang++ даже допускает неявное приведение типов между блоками и лямбда-выражениями.
#include <dispatch/dispatch.h>
void setup_callback(dispatch_block_t block)
{
// required to copy the block to the heap, otherwise it's on the stack
dispatch_block_t copy = [block copy];
// setup stuff here
// when you want to call the callback, do as if it was a function pointer:
// block();
}
int main()
{
MyClass* instance = [[MyClass alloc] init];
setup_callback(^{
[instance callback_method];
});
}
Это может потребовать некоторой доработки на стороне С++, чтобы принимать функторы (или просто блоки, если это проще) вместо указателей на функции.
Так как блоки создают замыкания, они очень удобны для такого рода работ.
Блоки — это расширение Apple для C, C++ и Objective-C. Подробнее о них см. здесь.
Используйте среду выполнения Objective-C для получения указателя функции на метод, который вы хотите вызвать.
Используйте среду выполнения Objective-C для доступа к указателю функции вашего селектора. Это более утомительно и требует, чтобы вы отслеживали три переменные (объект для вызова метода, используемый селектор и реализацию метода), но на самом деле это работает даже в том случае, если вы не можете использовать Objective-C. синтаксис.
Реализации метода Objective-C представляют собой указатели на функции с такой сигнатурой:
typedef void (*IMP)(id self, SEL _cmd, ...);
Где self
— это то, что вы ожидаете, _cmd
— это селектор, вызвавший вызов этого метода (переменная _cmd
на самом деле доступна во всех методах Objective-C, попробуйте), а остальное считается вариативным. Вам необходимо преобразовать IMP
переменных в соответствующую сигнатуру функции, потому что соглашение о вызовах для вариативных функций C не всегда соответствует соглашению о вызовах для вызовов методов Objective-C (вызов метода Objective-C является стандартным соглашение о вызовах функций для вашего компилятора, вероятно, либо cdecl
, либо соглашение о вызовах amd64, а соглашение о вызовах с переменным числом аргументов не всегда одинаково). reinterpret_cast
сможет это сделать.
Вот некоторый код, который я собрал для аналогичных целей. Он использует вариативные шаблоны С++ 11, чтобы помочь получить правильную сигнатуру функции.
#include <objc/runtime.h>
template<typename TReturnType, typename... TArguments>
auto GetInstanceMethodPointer(Class class, SEL selector) -> TReturnType (*)(id, SEL, TArguments...)
{
Method m = class_getInstanceMethod(class, selector);
IMP imp = method_getImplementation(m);
return reinterpret_cast<TReturnType (*)(id, SEL, TArguments...)>(imp);
}
int main()
{
MyClass* instance = [[MyClass alloc] init];
auto foo = GetInstanceMethodPointer<void>(
[MyClass class],
@selector(my_callback));
// foo is a void (*)(id, SEL) function pointer
foo(instance, @selector(my_callback));
}
Также позаботьтесь о том, чтобы ваш экземпляр не был nil
, прежде чем использовать вызов функции, потому что проверка nil
обрабатывается средой выполнения Objective-C. В данном случае мы его обходим.
Следите за объектом и SEL
Используйте -[NSObject performSelector:]
для обратного вызова. По сути, более простая версия решения для среды выполнения Objective-C.
void setup_callback(id object, SEL selector)
{
// do stuff
// to execute the callback:
// [object performSelector:selector];
}
int main()
{
MyClass* instance = [[MyClass alloc] init];
setup_callback(instance, @selector(my_callback));
}
Обертывание вашего вызова внутри функции C++
Я думаю, что это действительно не нуждается в каком-либо примере. Создайте функцию, которая принимает ваш тип объекта в качестве первого параметра, и вызовите для нее нужный метод. Аналогично решению SEL
, вам нужно отдельно отслеживать вызываемую функцию и объект, для которого ее вызывают.
person
zneak
schedule
30.08.2012