【问题标题】:call swift func from c++ with EXC_BAD_ACCESS(...)使用 EXC_BAD_ACCESS(...) 从 c++ 调用 swift func
【发布时间】:2016-07-06 23:37:09
【问题描述】:

我正在开发 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

在视图控制器中测试函数

run_swiftfunc

函数指针0x1300cd30

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

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

【问题讨论】:

标签: c++ ios swift


【解决方案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();   
    } 
 ...
 }

【讨论】:

    【解决方案2】:

    在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 ");
    }
    

    我建议您在使用完它后,将引用设为 nil,以防万一。

    另一种选择是使用 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
    

    【讨论】:

    • 添加 __strong 并添加 let 闭包:@convention(block) () -> Void = self.testfunc,仍然无法正常工作。
    • 尝试使用 Objective-C 运行时,但未声明“typeof”。
    • 已更新。我删除了typeof
    • 我的代码在 imp_implementationWithBlock 上编译失败。我现在使用 Block_copy 成功解决了这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-28
    • 2012-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多