【问题标题】:TVOS: Race condition at startupTVOS:启动时的竞争条件
【发布时间】:2016-01-21 20:02:32
【问题描述】:

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

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

【问题讨论】:

    标签: race-condition tvos tvml tvjs


    【解决方案1】:

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

    【讨论】:

    • 是的。这样可行。在本机方面,它似乎相对复杂,但它确实有效!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 2022-01-23
    • 2018-10-08
    相关资源
    最近更新 更多