网上有很多教程可以使之实现,但是没有一个清晰而客观的教程,因为那是我更愿意展示的案例。
我正在开发一个使用C API连接到服务网站并且具有回调功能的iOS应用,我的任务很简单,我必须在Swift代码上获取C代码中生成的事件。为此,我尝试了一些方法,目前正在尝试的方法如下。
场景
我有三个文件:wrapper.cpp
,Bridging-Header.h
和ViewController.swift
在Briding-Header.h
上,我声明了一个函数的指针。
Bridging-Header.h
void callback_t(void(*f)(unsigned char*));
在wrapper.cpp
上,我编写了代码以连接到Web并使用回调函数。因此,这是在断开连接时获得状态连接的回调方法。
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 :(得分:1)
首先,callback_t
不是标识符。我typedef
在任何地方都看不到。
其次,您需要某种方式告诉C ++回调是您的快速函数。为此,我将其作为参数传递给C ++函数,这与在Objective-C和Swift中的用法类似。否则,您需要将回调存储在全局变量中的某个位置,并让C ++访问它。
使用第一种将回调传递为参数的方法:
首先,我做了C ++头文件(Foo.h
。(不要删除ifdef
东西。.编译器在导入到Swift时使用C链接,但是在编译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)
}
})
}
}
工作正常。经过2秒钟后,从C ++调用了Swift代码。
使用将回调函数存储在全局变量中的第二种方法(我不屑一顾,但我们不要赘述)。
在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()
}
}