【问题标题】:Call to swift method from JavaScript hangs xcode and application从 JavaScript 调用 swift 方法会挂起 xcode 和应用程序
【发布时间】:2016-06-19 14:04:18
【问题描述】:

我正在使用 JavascriptCode 框架编写一个 iOS 应用程序(使用 xcode 7.3 和 swift 2.2)。从 swift 调用 javascript 方法很完美,但是当我从 javascript 调用 swift 方法时,xcode 只是显示一个“加载”类型的符号,没有任何反应。我需要“强制退出”xcode 才能摆脱这种状态。 我关注了https://www.raywenderlich.com/124075/javascriptcore-tutorialhttp://nshipster.com/javascriptcore/,我正在尝试非常简单的调用。

有人遇到过这种问题吗?

我的swift代码如下:

@objc protocol WindowJSExports : JSExport {
   var name: String { get set }
   func getName() -> String
   static func createWindowWithName(name: String) -> WindowJS
}

@objc class WindowJS : NSObject, WindowJSExports {
   dynamic var name: String
   init(name: String) {
       self.name = name
   }    
   class func createWindowWithName(name: String) -> WindowJS {
       return WindowJS(name: name)
   }    
   func getName() -> String {
       NSLog("getName called from JS context")
       return "\(name)"
   }
} 

我正在初始化上下文如下:

runContext = JSContext()
runContext.name = "test_Context"

windowToJs = WindowJS(name: "test")
runContext.setObject(windowToJs.self, forKeyedSubscript: "WindowJS")

如果我用下面的代码替换上面代码的最后两行而不实例化它,代码根本无法加载。

runContext.setObject(WindowJS.self, forKeyedSubscript: "WindowJS")

而javascript代码就这么简单

function check() {
    return WindowJS.getName()
}

我确实在 JS 函数检查中看到了断点,当调用 WindowJS.getName 时,xcode 变得无响应。

【问题讨论】:

  • JavaScript 调用是如何触发的?从 Swift 调用它(甚至作为副作用)是偶然触发的吗?例如,您是否有可能以 Swift->JS->Swift 循环结束?
  • @DarkDust 谢谢!这就是正在发生的事情。如何在 JSContext 中实现类似“WKWebView 中 JavaScript 中的 postMessage”的异步效果?

标签: xcode swift freeze javascriptcore


【解决方案1】:

可以通过在我的 swift 函数中添加以下代码来解决 setTimeout。

let setTimeout: @convention(block) (JSValue, Int) -> () = 
{ callback, timeout in
    let timeVal = Int64(timeout)
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeVal), dispatch_get_main_queue(), { callback.callWithArguments(nil)})
}

为了将本机代码暴露给 JS 上下文,我还添加了以下内容。

runContext.setObject(unsafeBitCast(setTimeout, AnyObject.self), forKeyedSubscript: "setTimeout")

然后一切正常。

【讨论】:

    【解决方案2】:

    您正在创建一个死锁,因为您正在从 Swift 调用 JavaScript 再返回 Swift。我不确定为什么会出现死锁,但我最近在 Mac 上遇到了类似的 WKWebView 问题。

    您需要将其解耦并使通信异步。这显然意味着在这种情况下你不能简单地从你的 JS 函数中返回一个值。

    要解耦,您可以使用 setTimeout 将 JavaScript 函数需要完成的工作推迟到当前的 runloop 迭代之外,从而打破僵局:

    function myFunction() {
      setTimeout(function() {
        // The actual work is done here.
        // Call the Swift part here.
      }, 0);
    }
    

    整个原生 ↔︎ JavaScript 通信非常非常棘手。如果可以的话,避免它。有一个名为 XWebView 的项目可以帮助您,因为它试图简化两个世界之间的桥梁。

    【讨论】:

    • 谢谢!我收到 setTimeout 的错误。您是否需要为 setTimeout( /*someCode */, 0) 工作做任何特别的事情?我也需要那个。
    • 你需要给它一个函数。在网上搜索一下,有很多关于如何使用它的示例。
    猜你喜欢
    • 2014-01-14
    • 1970-01-01
    • 2016-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-22
    相关资源
    最近更新 更多