我正在尝试编写一个通过JavaScriptCore运行JS的Swift程序。我希望在程序的两个部分之间共享内存,以便JS写入Swift中创建的类型化数组缓冲区,然后Swift对其进行读写操作。这将是一种命令缓冲区。
例如,这是一些伪代码,大致代表我打算做的事情:
// js
let buf;
let i = 0;
setup() {
buf = new Uint8Array(mem.alloc(N_BYTES));
}
frame() {
i = 0;
buf[i++] = some_command_enum;
}
// swift
func alloc(bytes : Int) -> the_memory {
// allocate bytes uints and save the memory here
// save a reference to the memory here
// return the memory to use in JS
}
问题是,每当我尝试将实现实际添加到alloc时,JS都会通过异常报告该函数未定义,这意味着我的工作方式出现问题。不可返回的功能很好,所以我对此有所保留。
这是我的错误实现(请参阅注释):
// swift
@objc protocol JSMemoryExports: JSExport {
static func alloc(_ byte_count: Int) -> JSObjectRef
static func free(_ memory: JSObjectRef)
}
class JSMemory: NSObject, JSMemoryExports {
// What is the correct return type?
class func alloc(_ byte_count: Int) -> JSObjectRef {
// temp
let jsContext = JS_Controller.js.ctx!
print("BYTE_COUNT", byte_count)
// allocating a typed array
let arr = JSObjectMakeTypedArray(jsContext.jsGlobalContextRef!, kJSTypedArrayTypeUint8Array, byte_count, nil)
// just testing here to see how I'd write to this buffer (Note: is this the fastest way, or is all this memory binding slow?:
// getting the raw bytes
let ptr = JSObjectGetTypedArrayBytesPtr(jsContext.jsGlobalContextRef!, arr, nil)
//let buf = JSObjectGetTypedArrayBuffer(jsContext.jsGlobalContextRef, arr, nil)
let u8Ptr = ptr!.bindMemory(to: UInt8.self, capacity: byte_count)
//u8Ptr[0] = 5
return arr!
}
}
...
jsContext["mem"] = JSMemory.self
// js
const buf = new Uint8Array(mem.alloc(8)) // JS Exception: TypeError: mem.alloc is not a function. (In 'mem.alloc(8)', 'mem.alloc' is undefined)
我已经看到了使用某些@convention
属性的函数绑定变体。我是否打算改用它?
正确的做法是什么?
除非您将来自不同来源的大量信息汇总在一起,否则文档不是很有帮助。看似可行的解决方案涉及使用在Swift中可调用的较旧C API的部分,不安全的指针,并确保绑定函数的返回值为JSValue?
。这是有道理的,因为JavaScript函数都返回一个对象null
,或 undefined
。可选类型反映了此行为。
这是我在进行中的代码,用于可能需要一些线索的任何人:
只是一个更新,我已经弄清楚了如何将旧的C API与新的受限于Swift的API混合使用。我尚未确定我没有泄漏内存,但是看来我已经找到了所需的东西。
如果您想知道:
@objc protocol JSMemoryExports: JSExport {
// note that I'm returning an optional
static func Uint8ArrayMake(_ count : JSValue) -> JSValue?
}
class JSMemory: NSObject, JSMemoryExports {
class func UInt8ArrayMake(_ count : JSValue) -> JSValue? {
guard !count.isUndefined && !count.isNull else {
return nil
}
let ref : JSValueRef = JSObjectMakeTypedArray(
JS_Controller.js.ctx.jsGlobalContextRef!,
kJSTypedArrayTypeUint8Array,
Int(count.toInt32()),
nil
)!
let ptr = JSObjectGetTypedArrayBytesPtr(
JS_Controller.js.ctx.jsGlobalContextRef!, ref, nil)
return JSValue(jsValueRef: ref, in: JS_Controller.js.ctx)
}
}
以下是一些有用的参考资料://https://www.raywenderlich.com/7181017-unsafe-swift-using-pointers-and-interacting-with-chttps://medium.com/@shoheiyokoyama/manual-memory-management-in-swift-c31eb20ea8f