2

I am currently developing a very simple Live Scores MAC OSX app for personal use where I show a bunch of labels (scores) on the touch bar. What I am trying to achieve in a few steps:

  1. Fetch live soccer scores from a 3rd party API every 30 seconds
  2. Parse the scores and make them into labels
  3. Update the touch bar with new scores

[Please note here that this app will not be published anywhere, and is only for personal use. I am aware of the fact that Apple strictly advises against such type of content in the Touch Bar.]

Here is the code that I wrote following basic Touch Bar tutorial from RW (https://www.raywenderlich.com/883-how-to-use-nstouchbar-on-macos). Skeleton of my code is picked from the RW tutorial:

  1. In WindowController (StoryBoard entry point), override makeTouchBar like this:
override func makeTouchBar() -> NSTouchBar? {
    guard let viewController = contentViewController as? ViewController else {
      return nil
    }
    return viewController.makeTouchBar()
  }
  1. In ViewController, which is also the Touch Bar Delegate, implement the makeTouchBar fn:
override func makeTouchBar() -> NSTouchBar? {
    let touchBar = NSTouchBar()
    touchBar.delegate = self
    touchBar.customizationIdentifier = .scoresBar
    touchBar.defaultItemIdentifiers = [.match1, .flexibleSpace, .match2, ... , .match10]

    return touchBar
  }
  1. NSTouchBarDelegate in ViewController. scores is where I store my fetched scores (See 5). I return nil for views if scores aren't fetched yet:
extension ViewController: NSTouchBarDelegate {

    func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {

        if (<scores not fetched yet>) {
            return nil
        }
        // matchNum is the match number for which I am showing scores for
        let customViewItem = NSCustomTouchBarItem(identifier: identifier)
        customViewItem.view = NSTextField(labelWithString: self.scores[matchNum ?? 0])
        return customViewItem
    }
}
  1. To fetch scores periodically I am running a scheduled task Timer in viewDidLoad() of my viewcontroller like this:
_ = Timer.scheduledTimer(timeInterval: 30.0, target: self, selector: #selector(ViewController.fetchScores), userInfo: nil, repeats: true)
  1. And finally, this is my fetchScores function that also makes a call to update the Touch Bar:
@objc func fetchScores() {
    let url = "<scores api end point>"
    Alamofire.request(url).responseJSON { response in
        if let json = response.result.value {
            // update self.scores here and fill it with latest scores

            if #available(OSX 10.12.2, *) {
                //self.touchBar = nil
                self.touchBar = self.makeTouchBar() // This is where I am calling makeTouchBar again to update Touch Bar content dynamically
            }

        }
    }

My understanding from the code above is that once I make a call to makeTouchBar in fetchScores and assign it to my viewcontroller's touchBar property, it should ideally call touchBar(:makeItemForIdentifier) delegate function to update the Touch Bar view (SO thread on this). But in my case, touchBar(:makeItemForIdentifier) is never called. The only time touchBar(:makeItemForIdentifier) is called is the first time, when makeTouchBar is called from my WindowController (See point 1 above). And since scores have not been retrieved yet, my touch bar remains empty.

kb_14
  • 267
  • 1
  • 6
  • 18

0 Answers0