TVOS:启动时的竞争条件

时间:2016-01-21 20:02:33

标签: race-condition tvos tvml tvjs

使用模板和TVML,我使用自己的加载页面启动我的应用程序,然后调用服务为用户创建主页面。

如果我在didFinishLaunchingWithOptions内启动对服务器的调用,则会收到错误ITML <Error>: undefined is not an object - undefined - line:undefined:undefined

由此我假设我对服务器的异步调用在javascript App.onLaunch函数完成之前完成,如果我在调用服务器之前强制等待一段时间,我只能让它工作。

这是AppDelegate方法:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        let appControllerContext = TVApplicationControllerContext()

        // our "base" is local
        if let jsBootUrl = NSBundle.mainBundle().URLForResource("application", withExtension: "js") {
            appControllerContext.javaScriptApplicationURL = jsBootUrl
        }
        let jsBasePathURL = appControllerContext.javaScriptApplicationURL.URLByDeletingLastPathComponent
        baseUrl = jsBasePathURL?.absoluteString
        appControllerContext.launchOptions["BASEURL"] = jsBasePathURL?.absoluteString

        appController = TVApplicationController(context: appControllerContext, window: window, delegate: self)

        // initiate conversation with the server
        myPageCreator = PageCreator()
        myPageCreator?.delegate = self
        myPageCreator?.startDataCall(baseUrl!)

        return true
    }

这是(有点模板)javascript函数:

App.onLaunch = function(options) {
    var javascriptFiles = [
        `${options.BASEURL}ResourceLoader.js`,
        `${options.BASEURL}Presenter.js`
    ];

    evaluateScripts(javascriptFiles, function(success) {
        if (success) {

            resourceLoader = new ResourceLoader(options.BASEURL);
            var index = resourceLoader.loadResource(`${options.BASEURL}myLoadingPage.xml.js`,
                function(resource) {
                    var doc = Presenter.makeDocument(resource);
                    doc.addEventListener("select", Presenter.load.bind(Presenter));
                    navigationDocument.pushDocument(doc);
                });
        } else {
            /* handle error case here */
        }
    });
}

现在,如果我将调用更改为didFinishLaunchingWithOptions中的服务器,并强制它等待,如下所示:

        ...
        // race condition hack:
        _ = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "testing", userInfo: nil, repeats: false)

        return true
    }

    // initiate conversation with the server
    func testing() {
        myPageCreator = PageCreator()
        myPageCreator?.delegate = self
        myPageCreator?.startDataCall(baseUrl!)
    }

..它会起作用。但我不喜欢那个解决方案!我该怎样做才能阻止这种竞争状况的发生?

1 个答案:

答案 0 :(得分:0)

您需要一种方法让Javascript与Swift通信,以便您知道 App.onLaunch 何时完成运行它的脚本。

didFinishLaunchingWithOptions 方法中运行此代码。它允许您在Javascript中调用 onLaunchDidFinishLoading()并在Swift中处理回调。

appController.evaluateInJavaScriptContext({(evaluation: JSContext) -> Void in
   let onLaunchDidFinishLoading : @convention(block) () -> Void = {
      () -> Void in
         //when onLaunchDidFinishLoading() is called in Javascript, the code written here will run.
         self.testing()
   }
   evaluation.setObject(unsafeBitCast(onLaunchDidFinishLoading, AnyObject.self), forKeyedSubscript: "onLaunchDidFinishLoading")

   }, completion: {(Bool) -> Void in
})


func testing() {
    myPageCreator = PageCreator()
    myPageCreator?.delegate = self
    myPageCreator?.startDataCall(baseUrl!)
}

App.onLaunch 内部,只需在模板加载完成后添加 onLaunchDidFinishLoading()

App.onLaunch = function(options) {
var javascriptFiles = [
    `${options.BASEURL}ResourceLoader.js`,
    `${options.BASEURL}Presenter.js`
];

evaluateScripts(javascriptFiles, function(success) {
    if (success) {

        resourceLoader = new ResourceLoader(options.BASEURL);
        var index = resourceLoader.loadResource(`${options.BASEURL}myLoadingPage.xml.js`,
            function(resource) {
                var doc = Presenter.makeDocument(resource);
                doc.addEventListener("select", Presenter.load.bind(Presenter));
                navigationDocument.pushDocument(doc);
                //ADD THE FOLLOWING LINE
                onLaunchDidFinishLoading();
            });
    } else {
        /* handle error case here */
    }
});
}