我正在开发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)!)
但我收到错误:"类型错误:getVastData 不是一个函数。(在'getVastData'中,'getVastData'是NSBlock的一个实例">
你知道我错在哪里,或者如何用 JS 的完成处理程序正确调用 Swift func 吗?
提前感谢, 米洛斯
首先,我们需要在 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 回调函数。简而言之,我们只是将 JS 值从我们的 TVML 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) {
...
}