TVOS:启动时的竞争条件

TVOS: Race condition at startup

使用模板和 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!)
    }

.. 它会起作用的。但我不喜欢那个解决方案!我能做些什么来阻止这种竞争条件的发生?

您需要一种方法让 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 */
    }
});
}