Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用Java脚本(TVML)中的完成处理程序调用Swift函数_Javascript_Swift_Tvos_Tvml - Fatal编程技术网

Javascript 使用Java脚本(TVML)中的完成处理程序调用Swift函数

Javascript 使用Java脚本(TVML)中的完成处理程序调用Swift函数,javascript,swift,tvos,tvml,Javascript,Swift,Tvos,Tvml,我正在开发tvOS应用程序(使用TVML),并尝试使用JS中的完成处理程序调用Swift函数 在TVApplicationControllerDelegate中,我尝试使用如下代码: let getVastData : @convention(block) (String, @escaping (UInt32, [String], String) -> ()) -> Void = { (url : String, _ completion:@escaping (_ dura

我正在开发tvOS应用程序(使用TVML),并尝试使用JS中的完成处理程序调用Swift函数

在TVApplicationControllerDelegate中,我尝试使用如下代码:

let getVastData : @convention(block) (String,  @escaping (UInt32, [String], String) -> ()) -> Void = {
    (url : String, _ completion:@escaping (_ duration: UInt32, _ addLinks: [String], _ videoLink: String) -> ()) -> Void in
    VastManager.shared.startParsing(with: url, completion)
}

jsContext.setObject(unsafeBitCast(getVastData, to: AnyObject.self), forKeyedSubscript: "getVastData" as (NSCopying & NSObjectProtocol)!)
但是我得到了一个错误:“TypeError:getVastData不是一个函数。(在'getVastData'中,'getVastData'是NSBlock的一个实例)

你知道我哪里错了,或者如何用JS的完成处理程序来纠正Swift func调用

提前感谢,,
Milos

首先,我们需要在jsContext中注册我们的Swift方法。我们的Swift方法需要接受回调函数,在我们的例子中是对JavaScipt值的引用,该值将在我们在Swift中的操作完成后被调用

let getVastData : @convention(block) (String, JSValue) -> Void = {
    (url : String, completion : JSValue) -> Void in
    VastManager.shared.startParsing(from: url, completion: completion)
}
jsContext.setObject(unsafeBitCast(getVastData, to: AnyObject.self), forKeyedSubscript: "getVastData" as (NSCopying & NSObjectProtocol))
因为我们希望异步调用它,所以需要存储该引用。我们将使用JSManagedValue存储JSValue以避免保留周期。JSManagedValue对象包装JSValue对象,并添加“条件保留”提供值的自动内存管理的行为。操作完成后,我们可以使用参数调用JavaScript回调函数。简单地说,我们只是将TVML JS中的JS值传递给Swift,存储并稍后调用

class VastManager: NSObject {

    var completion: JSManagedValue?
    var url: String?

    public func startParsing(from url: String, completion: JSValue) {
        self.completion = JSManagedValue(value: completion)
        self.url = url
    }
    ...

    func parserDidEndDocument(_ parser: XMLParser) {

        ...

        _ = self.completion?.value?.call(withArguments: [duration, ads, videoUrl])
    }
}
最后,我们可以从JavaScript调用Swift函数并传递回调函数

getVastData(vastTag, function(duration, adLinks, videoLink) {
   ...
}
// or
function updatePlayer(duration, adLinks, videoLink) {
   ...
}
getVastData(vastTag, updatePlayer) {
   ...
}

evaluate(inJavaScriptContext:)
块中调用完成处理程序的具体原因是什么?只需执行
completion.call(带参数:)
在我的应用程序中似乎工作得很好。@Anders您的方法更好/更简单,我将更新我的注释。另一个注释:我不确定您是否应该存储非托管的
JSValue
,因为它可以创建一个保留周期。相反,您最好将
completion
属性更改为
JSManagedValue
。我不是c完全确定您的设置,但查看文档并确定它是否与您的用例相关:@Anders。您是对的,我将完成更改为JSManagedValue。我对旧解决方案没有问题,但这可能会防止将来出现一些错误。