Как сделать указатель на функцию обратного вызова из C ++ для Swift?

Есть много учебных пособий, чтобы сделать это в Интернете, но ни одно не является ясным и объективным, потому что именно это я предпочитаю показать в моем случае.

Я разрабатываю приложение для iOS, которое использует C API для подключения к веб-сервису, и оно имеет функции обратного вызова, моя задача проста, я должен получать события, сгенерированные в коде C, в коде Swift. К этому я попробовал несколько способов, текущий способ, которым я пытаюсь, состоит в следующем.

сценарий

У меня есть три файла: wrapper.cpp, Bridging-Header.h а также ViewController.swift

На Briding-Header.h Я объявил указатель на функцию.

Bridging-header.h

void callback_t(void(*f)(unsigned char*));

На wrapper.cpp Я написал свой код для подключения к сети и использования функций обратного вызова. Так что это метод обратного вызова для получения состояния соединения при отключении.

wrapper.cpp

void callback_web_disconnected(unsigned char *c) {
printf("Disconnected %s",c);
// Here I want invoke a method to Swift code
callback_t(r); // But this not works
}

Это не компилируется, сообщение об ошибке: Use of undeclared identifier 'callback_t',

Если я попытаюсь написать: void callback_frame(unsigned char*);, linker command failed with exit code 1 ошибка происходит.

ViewController.swift

func callback_t(_ f: ((UnsafeMutablePointer<UInt8>?) -> Void)!) {
print("ARRIVED ON VIEWCONTROLLER!")
// Here I want get the error code (unsigned char*) passed as parameter
}

Я не могу импортировать Bridging-Header.h подать на wrapper.cpp потому что вызывают много конфликтов.

0

Решение

Первый, callback_t не является идентификатором. Я не вижу этого typedef в любом месте..
Во-вторых, вам нужен какой-то способ сказать С ++, что обратный вызов — это ваша быстрая функция. Для этого я передаю его в качестве параметра в функцию C ++, аналогично тому, как мы это делаем в Objective-C и Swift. В противном случае вам нужно где-то хранить обратный вызов в глобальной переменной и иметь доступ к нему в C ++.

Используя первый метод передачи обратного вызова в качестве параметра:

Сначала в заголовке C ++ (Foo.hЯ сделал (НЕ удаляйте ifdef вещи … компилятор использует связь C при импорте в Swift, но при компиляции стороны C ++ он будет искажен, поэтому, чтобы заставить его использовать связь C, мы extern "C" код):

#ifndef Foo_hpp
#define Foo_hpp

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef void(*callback_t)(const char *);
void callback_web_disconnected(callback_t);

#ifdef __cplusplus
} // extern "C"#endif

#endif /* Foo_hpp */

Тогда в файле реализации (Foo.cpp) Я сделал:

#include "Foo.h"#include <thread>
#include <iostream>

#ifdef __cplusplus
extern "C" {
#endif

void callback_web_disconnected(callback_t callback)
{
std::thread t = std::thread([callback] {
std::this_thread::sleep_for(std::chrono::seconds(2));

if (callback)
{
callback("Hello World");
}
});

t.detach();
}

#ifdef __cplusplus
} // extern "C"#endif

Затем в ViewController.swift я сделал:

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

callback_web_disconnected({
if let ptr = $0 {
let str = String(cString: ptr)
print(str)
}
})
}
}

Работает нормально. Код Swift вызывается из C ++ через 2 секунды.


Используя второй метод хранения обратного вызова в глобальной переменной (которую я презираю, но давайте не будем вдаваться в это) ..

В Foo.h Я сделал:

#ifndef Foo_hpp
#define Foo_hpp

#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef void(*callback_t)(const char *);
callback_t globalCallback; //Declare a global variable..

void callback_web_disconnected();

#ifdef __cplusplus
} // extern "C"#endif

#endif /* Foo_hpp */

В Foo.cpp Я сделал:

#include "Foo.h"#include <thread>
#include <iostream>

#ifdef __cplusplus
extern "C" {
#endif

void callback_web_disconnected()
{
std::thread t = std::thread([] {
std::this_thread::sleep_for(std::chrono::seconds(2));

if (globalCallback)
{
globalCallback("Hello World");
}
});

t.detach();
}

#ifdef __cplusplus
} // extern "C"#endif

В ViewController.swift, Я сделал:

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

//Set the globalCallback variable to some block or function we want to be called..

globalCallback = {
if let ptr = $0 {
let str = String(cString: ptr)
print(str)
}
}

//Trigger our test.. I guess your C++ code will be doing this anyway and it'll call the globalCallback.. but for the sake of this example, I've done it here..
callback_web_disconnected()
}
}
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]