2016-01-21 80 views
0

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

如果我发起呼叫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!) 
    } 

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

回答

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 */ 
    } 
}); 
} 
+0

是的。这样可行。它似乎比较复杂,在本地,但它的作品! – coco