如何从c ++类访问Swift对象?

时间:2016-08-28 09:27:20

标签: c++ swift

我想改变一些对象(标签,按钮......)的属性,我是用c ++代码创建的。所以我需要一种运行ViewController-class-internal方法的方法。

有没有正确的方法呢?还有其他可能吗?

我尝试过使用回调,但ViewController类中的全局和内部之间始终存在这种障碍。提前谢谢!

编辑: 由于我不知道如何使用c ++代码访问swift类,我无法提供任何适当的示例,但我想到了类似的东西(伪代码):

在c ++中:

int main(){
    say_hello();
}

并在Swift中:

class ViewController: NSViewController {
    @IBOutlet weak var label: NSTextField!
    func say_hello(){
        label.stringValue = "Hello"
    }
}

1 个答案:

答案 0 :(得分:2)

这是一个过于简单的示例,说明如何使用Objective-C ++包装器完成此操作,如Richard所建议的那样。这里没有解决内存管理和线程安全方面以及许多其他问题。在此示例中,Swift和C ++类实例之间存在一对一的关系。此外,Swift对象指针用作标识符来决定哪个Swift对象应该接收通知。这有点危险,请参阅下面的代码中的注释。使用Objective-C ++包装器中更复杂的数据结构来维护Swift和C ++对象之间的连接,可以轻松解决这种危险并支持除1对1之外的关系。

首先,这是一个触发Swift代码更改的C ++类:

typedef void (*cb_t)(const char *, void *);

class MyClassCPP {
public:
    MyClassCPP(cb_t callBack, void * p) : myCallBack(callBack), clientPtr(p) {}
    void doWork();  // perform some work and invoke the callback
private:
    cb_t myCallBack;
    void * clientPtr;
};
void MyClassCPP::doWork() {
    myCallBack("C++ code at work...", clientPtr);
}

这是一个Objective-C ++包装器接口,应该通过桥接头直接或间接地使Swift代码可见。请注意,它不引用任何C ++类型。

@class SwiftClass;  // forward declaration
                    // can't include *-Swift.h in a header

@interface OCWrapper : NSObject

-(instancetype)init:(SwiftClass * )sc;
-(void)requestWorkFromCPP;

@end

这是包装器实现。它确实引用了C ++类型。我们不能提供Swift全局函数作为C ++代码的回调,但我们可以为此提供Objective-C ++全局函数。

// Extension that deals with C++ specifics that can't be visible to Swift
@interface OCWrapper ()
{
    MyClassCPP * myClassCPP;
}
@end

void callBack(const char * msg, void * swiftClient)
{
    // Danger: what if swiftClient does not point to a SwiftClass instance?
    [(__bridge SwiftClass*)swiftClient sayHello: 
       [[NSString alloc] initWithBytes: msg length:strlen(msg)
        encoding:NSASCIIStringEncoding]];
}

@implementation OCWrapper

-(instancetype)init:(SwiftClass * )sc
{
    myClassCPP = new MyClassCPP(callBack, (__bridge void*)sc);
    return self;
}

-(void)requestWorkFromCPP{
    myClassCPP->doWork();
}

@end

以上内容应该在Objective-C ++文件中。创建一个Objective-C文件,然后将其重命名为.mm扩展名。您还需要包含* -Swift.h头文件,因此Objective-C ++可以使用Swift类型。

最后,这里有一些通过Objective-C ++包装器使用C ++代码的Swift代码:

// This is like your Swift view controller
class SwiftClass : NSObject
{
    var label = "[Empty]"

    var name : String;
    init(name : String) {
        self.name = name
    }

    func sayHello(greeting : String) {
        label = "SwiftClass named " + name + " received greeting: " + greeting
    }
}
...
        let sc = SwiftClass( name : "Zero")
        let ocWrapper = OCWrapper(sc)
        let sc1 = SwiftClass( name : "One" )
        let ocWrapper1 = OCWrapper(sc1)

        ocWrapper1.requestWorkFromCPP()
        print("The label value from C++: \(sc1.label)")

        ocWrapper.requestWorkFromCPP()
        print("The label value from C++: \(sc.label)")
...