请教使用 JavascriptCore 导出函数到 JS 环境,如果传递参数是 Object 时遇到的问题?

问答adow • 于 2015-10-22 05:15:50 +0800 • 最后由 iBcker2015-10-25 07:05:59 +0800 5006 阅读

如果我们想通过 JavascriptCore 导出一个函数到 Javascript 中,这个 js 的函数调用的时候应该是这样的(只有一个参数)

share({
    text:"test text",
    url:"http://codingnext.com",
    callback:function(){
        console.log('test func');
    }
});

那我们可以这样导出这个函数,由于参数是一个 Javascript Object,所以我在 Swift 中定义为一个字典 [String:AnyObject]。

let block : @convention(block) ([String:AnyObject]) -> () = {
        (d) -> () in
        let text = d["text"] as? String ?? ""
        let url = d["url"] as? String
        let callback = d["callback"] as? JSValue
        callback?.callWithArguments(nil)
    }

self.js.setObject(unsafeBitCast(block, AnyObject.self), forKeyedSubscript: "share")

事实上,在 Swift 中获取 text,url 都是正确的,但是 callback 却是 nil,后来我发现 d["callback"] 并不是 JSValue, 也不是 ()->(), 而是 _NSDictionaryM,这个类型让我不知道改如何处理了,我发现他里面没有任何key和value。

所以我的问题在这个 Javascript Object 参数,如果这个 object 的有一个属性(这里的 callback)是 function object 的话(我不知道是不是这么称呼的),在 JavascriptCore 转换到 Swift 或者 Objective-C 过来不知道改如何处理了。

如果 不是这种 object 里包含一个 function object,而是直接使用闭包作为参数的话,比如

share('test text','http://codingnext.com', function(){
    console.log('test func');
});

那我在 Swift 中只要把这个参数类型定义为 JSValue,然后调用 callWithArguments(nil); 就可以了,而当把这个闭包放在 Object 的属性里就不知道怎么弄了。

请教这样的类型该如何处理呢?

回复: 7
  • iBcker 2015-10-22 06:57:01 +0800

    好像挺有意思,我来琢磨一下

  • iBcker 2015-10-24 10:26:04 +0800

    前几天太忙忘记看了,补一下,换了个思路,希望能帮到你 let jscontent = JSContext() let block : @convention(block) () -> () = { let args = JSContext.currentArguments() if let arg = args.first { let text = arg["text"] let url = arg["url"] let callback = arg.valueForProperty("callback") let ret = callback.callWithArguments([]) print("\(text),\(url),\(ret)") } } jscontent.setObject(unsafeBitCast(block, AnyObject.self), forKeyedSubscript: "share") jscontent.evaluateScript("share({text:\"test text\",url:\"http://codingnext.com\",callback:function(){ return 3;}});") => Optional(test text),Optional(http://codingnext.com),3

  • dugege 2015-10-24 18:29:59 +0800

    @iBcker 你这个办法和楼主那个办法好像基本一样,那看起来像苹果的一个bug?

  • dugege 2015-10-24 18:50:29 +0800

    @dugege 不清楚,以前没怎么注意过这种情况~不过可以肯定不是Swift的问题,试了下OC结果也一样·

  • iBcker 2015-10-24 18:53:16 +0800

    @dugege 不清楚,以前没怎么注意过这种情况~不过可以确定不是Swift的问题,试了下OC结果也一样

    ``` JSContext *context = [[JSContext alloc] init]; context[@"share"] = ^(NSDictionary *d) { NSLog(@"+++++++Begin Log+++++++"); NSLog(@"%@",[d[@"callback"] class]); };

    [context evaluateScript:@"share({text:\"test text\",url:\"http://codingnext.com\",callback:function(){ return 3;}});"]; ```

    +++++++Begin Log+++++++
    __NSDictionaryM

  • adow 2015-10-25 06:23:00 +0800

    @iBcker @dugege

    谢谢,的确把传入的参数作为 JSValue,然后使用 valueForProperty("callback") 的确可以获取到这个函数的 JSValue, 我也不明白为啥 [String:AnyObject] 这样的方式对于传入 function 就会变成 _NSDictionaryM,我感觉这是不是 JavascriptCore 的 Bug? 我现在就把这个参数作为 JSValue, 然后取得各个 property 的方式来做了,看上去这样比较靠谱和统一,之前我都没注意到还有 valueForProperty 这个方法,看到 @iBcker 的回复我才从 JSValue.h 里面看到了这个,谢谢。

    再次感谢回复,我为这个问题困扰了好几天,然后发了 v2ex.com, segmentfault.com 和 这里,只有这里回复了这个帖子。

  • iBcker 2015-10-25 07:05:59 +0800

    @adow :-)

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,见 Emoji cheat sheet
  • @name 会链接到用户页面,并会通知他
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
Ctrl+Enter