使用EXC_BAD_ACCESS(...)从c ++调用swift func

时间:2016-07-06 23:37:10

标签: c++ ios swift

我正在研究xcode8 swift 3.0项目。它需要访问一个C ++库,它需要一个回调函数来异步地将数据发送回swift调用者。 如果在RegisterCallBack函数内调用它,则回调会起作用。 但是,如果它在RegisterCallBack函数之外调用它会崩溃。

在我的swift文件ViewController.swift

override func viewDidLoad() {
    super.viewDidLoad()
    var closure: () -> Void = testfunc;
    RegisterCallBack(closure)

    run_swiftfunc()
}
func testfunc(){
    print("test func in view contriller ");
}
....

//在我的wrapper.h文件中

...
void run_swiftfunc();
void RegisterCallBack(void (^closure)());
...

//在我的wrapper.cpp文件中

extern "C" {
typedef void (^callbackfunc)();
callbackfunc swiftFunc;
void RegisterCallBack(void (^closure)()){
    swiftFunc = closure;
    printf("function pointer 0x%x \n", (void*) swiftFunc);
    swiftFunc();  //works well 
}
void run_swiftfunc(){
   printf("function pointer 0x%x \n", (void*) swiftFunc);
   swiftFunc();   // fail, EXC_BAD_ACCESS
} 
...
}

//日志打印: RegisterCallBack函数指针0x1300cd30

run_swiftfunc

函数指针0x1300cd30

在视图控制器中测试func

run_swiftfunc

函数指针0x1300cd30

(lldb)----> EXC_BAD_ACCESS(code = ..

swiftfunc地址相同都是0x1300cd30。如何保存swiftfunc块?

2 个答案:

答案 0 :(得分:1)

我发现块只是堆栈,所以只能在函数范围内工作。我最终使用Block_copy来避免这个问题。 现在我可以使用异步回调函数来调用c ++中的swift函数

//在我的wrapper.cpp文件中

 #include <Block.h>
 extern "C" {
         typedef void (^callbackfunc)();
         callbackfunc swiftFunc;
         void RegisterCallBack(void (^closure)()){
         swiftFunc = Block_copy(closure);
         printf("function pointer 0x%x \n", (void*) swiftFunc);
        swiftFunc();  //works well 
    }

    void run_swiftfunc(){
         printf("function pointer 0x%x \n", (void*) swiftFunc);
         swiftFunc();   
    } 
 ...
 }

答案 1 :(得分:0)

在cpp文件中创建闭包__strong

//
//  TestCallbacks.h
//  XIO
//
//  Created by Brandon T on 2016-07-06.
//  Copyright © 2016 XIO. All rights reserved.
//

#ifndef TestCallbacks_h
#define TestCallbacks_h


#ifdef __cplusplus
extern "C" {
#endif
    void run_swiftfunc();
    void RegisterCallBack(void (^closure)());
#ifdef __cplusplus
}
#endif

#endif /* TestCallbacks_h */


//
//  TestCallbacks.mm
//  XIO
//
//  Created by Brandon T on 2016-07-06.
//  Copyright © 2016 XIO. All rights reserved.
//

#include "TestCallbacks.h"
#include <cstdio>

#ifdef __cplusplus
extern "C" {
#endif

    typedef void (^callbackfunc)();

    __strong callbackfunc swiftFunc;

    void RegisterCallBack(void (^closure)()) {
        swiftFunc = closure;
        printf("function pointer %p \n", (void*) swiftFunc);
        swiftFunc();
    }

    void run_swiftfunc() {
        printf("function pointer %p \n", (void*) swiftFunc);
        swiftFunc();

        swiftFunc = nil;
    }

#ifdef __cplusplus
}
#endif

然后我在桥接标题中包含TestCallbacks.h ..

然后我快速地做:

override func viewDidLoad() {
    super.viewDidLoad()
    let closure: @convention(block) () -> Void = self.testfunc
    RegisterCallBack(closure)
    run_swiftfunc()
}

func testfunc(){
    print("test func in view contriller ");
}

我建议你在使用完毕后,为了以防万一,你的参考文献都是零。

另一个选择是使用Objective-C运行时:

#include "TestCallbacks.h"
#include <cstdio>
#import <objc/runtime.h>



#ifdef __cplusplus
extern "C" {
#endif

    typedef void(*callback)(id, SEL)
    callback swiftCallback;

    void RegisterCallBack(void (^closure)()) {

        swiftCallback = (callback)imp_implementationWithBlock(closure);
        printf("function pointer %p \n", (void *) swiftCallback);
        swiftCallback(nil, nil);
    }

    void run_swiftfunc() {
        printf("function pointer %p \n", (void *) swiftCallback);
        swiftCallback(nil, nil);

        imp_removeBlock((IMP)swiftCallback);
    }

#ifdef __cplusplus
}
#endif