2

在网上有很多教程可以做到这一点,但没有一个是清晰客观的,因为我更喜欢展示我的案例。

我正在开发一个使用 C API 连接到服务 Web 的 iOS 应用程序,它具有回调函数,我的任务很简单,我必须在 Swift 代码上获取用 C 代码生成的事件。为此,我尝试了一些方法,我正在尝试的当前方法如下。

设想

我有三个文件wrapper.cppBridging-Header.hViewController.swift

Briding-Header.h我声明了一个函数的指针。

桥接-Header.h

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

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
}

它没有编译,错误消息: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
    }

我无法导入Bridging-Header.h文件,wrapper.cpp因为会导致很多冲突。

4

1 回答 1

4

首先,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 */

然后在实现文件(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()
    }
}
于 2018-12-06T23:34:33.597 回答