簡體   English   中英

如何在 JavaScriptCore 和 Swift 之間共享數組內存?

[英]How to share array memory between JavaScriptCore and Swift?

我正在嘗試編寫一個通過 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? s。 這是有道理的,因為 JavaScript 函數都返回一個對象、 nullundefined 可選類型反映了這種行為。

這是我為可能需要一些潛在客戶的任何人准備的代碼:

只是為了更新,我想出了如何將舊的 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
        )!

        // if you want to modify the data
        // let ptr = JSObjectGetTypedArrayBytesPtr(
        //    JS_Controller.js.ctx.jsGlobalContextRef!, ref, nil
        // )

        return JSValue(jsValueRef: ref, in: JS_Controller.js.ctx)    
    }
}

以下是一些有用的參考資料:

Swift 中的指針
Swift 中的手動內存管理

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM