Aug*_*sto 2 c++ ios swift objective-c-swift-bridge
网上有很多教程可以做到这一点,但没有一个是清晰客观的,因为我更喜欢展示我的案例。
我正在开发一个 iOS 应用程序,它使用 C API 连接到服务 Web,它具有回调函数,我的任务很简单,我必须在 Swift 代码上获取 C 代码生成的事件。对此我尝试了一些方法,目前我正在尝试的方法如下。
设想
我有三个文件:wrapper.cpp、Bridging-Header.h和ViewController.swift
我声明Briding-Header.h了一个函数的指针。
桥接标头.h
void callback_t(void(*f)(unsigned char*));
Run Code Online (Sandbox Code Playgroud)
我wrapper.cpp编写了代码来连接到网络并使用回调函数。所以这是断开连接时获取状态连接的回调方法。
包装器.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
}
Run Code Online (Sandbox Code Playgroud)
它无法编译,错误消息:Use of undeclared identifier 'callback_t'。
如果我尝试 write: 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
}
Run Code Online (Sandbox Code Playgroud)
我无法导入Bridging-Header.h文件,wrapper.cpp因为会导致很多冲突。
首先,callback_t不是标识符。我在任何地方都没有看到它typedef。其次,您需要某种方式告诉 C++ 回调是您的 swift 函数。为此,我将其作为参数传递给 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 */
Run Code Online (Sandbox Code Playgroud)
然后在实现文件(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
Run Code Online (Sandbox Code Playgroud)
然后在 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)
}
})
}
}
Run Code Online (Sandbox Code Playgroud)
效果很好。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 */
Run Code Online (Sandbox Code Playgroud)
在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
Run Code Online (Sandbox Code Playgroud)
在 中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()
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2234 次 |
| 最近记录: |