swift - macOS Bundles 之间的双向数据交换 (swift)
问题描述
如何在 macOS 捆绑包之间传递数据?
例如:MyApp.app 将数据发送到 MyBundle.bundle 中的函数或类初始化程序,后者对其执行自己的逻辑。它甚至可以返回一个值,然后 MyApp.app 可以进一步处理。
例如,MyBundle 中的一个函数(不嵌套在任何其他声明中):
void initialise(unsigned int frameCount) {…} // not a class initialiser btw
我努力了:
在 MyBundle 中声明一个类,然后使用以下命令将其加载到 MyApp 中
Foundation.Bundle
:let class = (Bundle(url: url)!.classNamed("MyClass")! as! NSObject.Type).init() // class is an instance of NSObject, but I can override the `init()` method // (in MyBundle) to do whatever. I have not found a way to implement an // initialiser with parameters, and it still be recognised here.
在 MyBundle 中声明一个函数并使用
CFBundleGetFunctionPointerForName
它来检索它。var bundles = CFBundleCreateBundlesFromDirectory(kCFAllocatorDefault, bundleDirectory, bundleExtension)! as Array var bundle1 = bundles.first! as! CFBundle var untypedFunctionPointer = CFBundleGetFunctionPointerForName(bundle, "initialise" as CFString)! let imp = unsafeBitCast(untypedFunctionPointer, to: IMP.self) let function = unsafeBitCast(imp, to: (@convention(c)(CUnsignedInt) -> Void).self) // If I specify parameters here, pass them in below, then try to use them in my objective c function, I get exc_bad_access. function(CUnsignedInt(1.0)) // Will work only when not trying to access parameters in the original objective c function. // Whatever @convention(c) function signature I use, the parameters are unusable in Objective C.
两者的关键问题是我无法将数据作为参数传递。因此,打印语句将起作用,但无法使用参数。
编辑:接受的答案显示了调用函数指针的正确方法。我谈到的崩溃是由于使用了没有正确桥接到 C 语言家族的类型的结果,所以如果有疑问,请坚持使用 Foundation 库中的 NSNumber、NSString 等。
解决方案
根据您的问题Call Swift function from Bundle和https://stackoverflow.com/a/56281093/5329717中的评论,我认为您是在 Swift 中动态调用函数指针或带UnsafeBufferPointer
参数的 Objective-c 方法之后。
首先UnsafeBufferPointer
将制作一个副本,因此为了互操作,我建议OpaquePointer
改用。
假设函数指向带有签名的指针大小写void cFunction(void* arg)
:
let fakeIMP = unsafeBitCast(functionToPointerAddress, to: IMP.self)
unsafeBitCast(fakeIMP,to:(@convention(c)(OpaquePointer)->Void).self)(bufferArg)
假设静态objective-c方法:
let receiverClass = NSClassFromString("SomeClass")
let selector: Selector = NSSelectorFromString("selectorArg:")
let methodIMP: IMP! = method_getImplementation(class_getClassMethod(receiverClass, selector))
unsafeBitCast(methodIMP,to:(@convention(c)(AnyClass?,Selector,OpaquePointer)->Any).self)(receiverClass,selector, bufferArg)
对于您提供的 C 签名
void initialise(unsigned int frameCount);
尝试这个:
let imp = unsafeBitCast(functionToPointerAddress, to: IMP.self)
unsafeBitCast(imp,to:(@convention(c)(Int)->Void).self)(1)
推荐阅读
- c# - 从 iOS 到 Wcf 服务的 Xamarin.Forms 连接
- html - 之间有空格的盒子(不同的宽度/高度)
- angular - 从字符串动态创建 Angular 组件
- python - 同时处理 Python
- java - 阿帕奇骆驼 ?transacted=true
- c# - 如何在一周中的特定日子为每个第一/第二/第三/第四周创建重复工作?
- javascript - 用于访问从模态框设置的 HTML 值的 JavaScript
- angular - 如何使用 tslint 在特定文件中导入黑名单
- node.js - 需要帮助在窗口上运行 github 项目
- python - 性能比较 Static Typing Python 3.6+ vs Cython