【问题标题】:Bidirectional data exchange between macOS Bundles (swift)macOS Bundles 之间的双向数据交换 (swift)
【发布时间】:2020-05-31 20:08:18
【问题描述】:

如何在 macOS Bundle 之间传递数据?

例如:MyApp.app 将数据发送到 MyBundle.bundle 中的函数或类初始化程序,后者对其执行自己的逻辑。它甚至可以返回一个值,然后 MyApp.app 可以进一步处理。

例如,MyBundle 中的一个函数(不嵌套在任何其他声明中):

    void initialise(unsigned int frameCount) {…} // not a class initialiser btw

我试过了:

  • 在 MyBundle 中声明一个类,然后使用 Foundation.Bundle 在 MyApp 中加载它:

    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 等。

【问题讨论】:

    标签: swift bundle foundation


    【解决方案1】:

    根据您的问题 Call Swift function from Bundlehttps://stackoverflow.com/a/56281093/5329717 中的 cmets,我认为您是在 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)
    

    【讨论】:

    • @Div 请在您的问题中包含原始 C 函数/objective-C 方法签名
    • 非常感谢您展示这项技术。原来崩溃是由于使用了与 Objective-C 和 Foundation 不兼容的类型,所以现在我只会使用 NSNumber、NSArray 等。
    猜你喜欢
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    相关资源
    最近更新 更多