How to update a Status Item created by AppDelegate from NSViewController












0















I'm trying to create a Countdown Timer application that runs in the Menu Bar, with no window or dock icon. I've been building this off of mostly tutorials I find online and I know the code is kind of messy (I plan to clean up after it functions properly). The issue I'm running into. In the AppDelegate I create the StatusBar item with no issue, but I can't figure out how to update it from the viewController. It instead is creating a new StatusBar item.



//AppDelegate info



class AppDelegate: NSObject, NSApplicationDelegate
{

let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
let popover = NSPopover()

func applicationDidFinishLaunching(_ aNotification: Notification)
{
menuBarRefresh(self)
}

func menuBarRefresh(_ sender: Any?)
{
if let button = item.button
{
button.image = NSImage(named: NSImage.Name("2"))
//button.title = initialTime.stringValue
button.action = #selector(togglePopover(_:))
}
popover.contentViewController = TimerViewController.freshController()
}

@objc func togglePopover(_ sender: Any?)
{
if popover.isShown
{
closePopover(sender: sender)
}
else
{
showPopover(sender: sender)
}
}

func showPopover(sender: Any?)
{
if let button = item.button
{
popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
}
}

func closePopover(sender: Any?)
{
popover.performClose(sender)
}


//Controller code



import Cocoa
import AVFoundation

//Checking to ensure entered data is numeric
extension String
{
var isNumeric: Bool
{
let range = self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted)
return (range == nil)
}
}

class TimerViewController: NSViewController
{

//Here's the texts fields for the user to enter content.
@IBOutlet var hourInput: NSTextField!
@IBOutlet var minuteInput: NSTextField!
@IBOutlet var secondInput: NSTextField!

//This is the label used to display the counter
@IBOutlet var initialTime: NSTextField!

//Here are the variables we're going to need
var hours = Int() //Place holder for the hours
var minutes = Int() //Place holder for the hours
var seconds = Int() //Place holder for the hours
var timer = Timer() //The timer we'll use later
var audioPlayer = AVAudioPlayer() //The audio player
var timeRemaining = Int() //Place holder for the total 'seconds' to be counted
var firstRun = Bool()

let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

override func viewDidLoad()
{
super.viewDidLoad()
getData() //Pull last saved time from Core Data and load it.
hourInput.stringValue = "(hours)" //Loading the hours into the hours field
minuteInput.stringValue = "(minutes)" //Loading the minutes into the minutes field
secondInput.stringValue = "(seconds)" //Loading the seconds into the seconds field
initialTime.stringValue = "00:00:00" //Resetting the 'counter' to 0
firstRun = true
updateStatusBar(self)

//Here we load up the audio file for the 'done' chime. If not available we print the catch
do
{
let audioPath = Bundle.main.path(forResource: "Done", ofType: "m4a")
try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath!))
}
catch
{
print("No Joy")
}
/* if let button = item.button
{
button.image = NSImage(named: NSImage.Name("2"))
button.title = initialTime.stringValue
button.action = #selector(togglePopover(_:))
}
*/ }

}

// MARK: Storyboard instantiation

extension TimerViewController
{
static func freshController() -> TimerViewController
{
let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil)
let identifier = NSStoryboard.SceneIdentifier("TimerViewController")
guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? TimerViewController
else
{
fatalError("Why can't I find TimerViewController? - Check Main.storyboard")
}
return viewcontroller
}
}

//Button actions follow

extension TimerViewController
{
@IBAction func clearButton(_ sender: Any)
{
clearFields()
timer.invalidate()
audioPlayer.stop()
}

@IBAction func pauseButton(_ sender: Any)
{
timer.invalidate()
}

@IBAction func quitButton(_ sender: Any)
{
exit(0)
}

@IBAction func startButton(_ sender: Any)
{
grabData()
setData()

timeRemaining = (hours*3600)+(minutes*60)+seconds

if timeRemaining <= 0
{
initialTime.stringValue = "Enter Time"
}

else
{
displayTime()

timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.startCountDown), userInfo: nil, repeats: true)

clearFields()
updateStatusBar(self)
}
}
}

//MARK: Other Functions

extension TimerViewController
{
func displayTime()
{
let secondsDisplay = String(format: "%02d", (timeRemaining%60))
let minutesDisplay = String(format: "%02d", (timeRemaining%3600)/60)
initialTime.stringValue = "(timeRemaining/3600):(minutesDisplay):(secondsDisplay)"
}

func grabData()
{
hours = hourInput.integerValue
minutes = minuteInput.integerValue
seconds = secondInput.integerValue
}

func clearFields()
{
hourInput.stringValue = ""
minuteInput.stringValue = ""
secondInput.stringValue = ""
initialTime.stringValue = "00:00:00"
}

func setData()
{
setHour()
setMinute()
setSecond()
}

func getData()
{
getHour()
getMinute()
getSecond()
}

@objc func showTimer(_ sender: Any?)
{
print("Are we here")
}
@objc func startCountDown()
{

timeRemaining -= 1
displayTime()
updateStatusBar(self)
print(timeRemaining)

if timeRemaining == 0
{
timer.invalidate()
audioPlayer.play()
}
}

/* func setNeedsStatusBarAppearanceUpdate()
{
button.image = NSImage(named: NSImage.Name("2"))
button.action = #selector(showTimer(_:))
}
*/
func updateStatusBar(_ sender: Any?)
{
if let button = item.button
{
button.image = NSImage(named: NSImage.Name("2"))
button.action = #selector(showTimer(_:))
button.title = initialTime.stringValue
}

//let menu = NSMenu()
//menu.addItem(NSMenuItem(title: "Clear Timer", action: #selector(AppDelegate.theDv2), keyEquivalent: "R"))
//menu.addItem(NSMenuItem(title: "Quit Timer", action: #selector(AppDelegate.quit), keyEquivalent: "Q"))
//item.menu = menu
}

}


//There's a bunch of CoreData stuff after here but I left that out. I'm just using CoreData mainly to learn how to and functional reason is to store and load the last used time



As it currently works, I get two StatusBar items instead of creating one with the AppDelegate then updating that one from the ViewController.










share|improve this question



























    0















    I'm trying to create a Countdown Timer application that runs in the Menu Bar, with no window or dock icon. I've been building this off of mostly tutorials I find online and I know the code is kind of messy (I plan to clean up after it functions properly). The issue I'm running into. In the AppDelegate I create the StatusBar item with no issue, but I can't figure out how to update it from the viewController. It instead is creating a new StatusBar item.



    //AppDelegate info



    class AppDelegate: NSObject, NSApplicationDelegate
    {

    let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
    let popover = NSPopover()

    func applicationDidFinishLaunching(_ aNotification: Notification)
    {
    menuBarRefresh(self)
    }

    func menuBarRefresh(_ sender: Any?)
    {
    if let button = item.button
    {
    button.image = NSImage(named: NSImage.Name("2"))
    //button.title = initialTime.stringValue
    button.action = #selector(togglePopover(_:))
    }
    popover.contentViewController = TimerViewController.freshController()
    }

    @objc func togglePopover(_ sender: Any?)
    {
    if popover.isShown
    {
    closePopover(sender: sender)
    }
    else
    {
    showPopover(sender: sender)
    }
    }

    func showPopover(sender: Any?)
    {
    if let button = item.button
    {
    popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
    }
    }

    func closePopover(sender: Any?)
    {
    popover.performClose(sender)
    }


    //Controller code



    import Cocoa
    import AVFoundation

    //Checking to ensure entered data is numeric
    extension String
    {
    var isNumeric: Bool
    {
    let range = self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted)
    return (range == nil)
    }
    }

    class TimerViewController: NSViewController
    {

    //Here's the texts fields for the user to enter content.
    @IBOutlet var hourInput: NSTextField!
    @IBOutlet var minuteInput: NSTextField!
    @IBOutlet var secondInput: NSTextField!

    //This is the label used to display the counter
    @IBOutlet var initialTime: NSTextField!

    //Here are the variables we're going to need
    var hours = Int() //Place holder for the hours
    var minutes = Int() //Place holder for the hours
    var seconds = Int() //Place holder for the hours
    var timer = Timer() //The timer we'll use later
    var audioPlayer = AVAudioPlayer() //The audio player
    var timeRemaining = Int() //Place holder for the total 'seconds' to be counted
    var firstRun = Bool()

    let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

    override func viewDidLoad()
    {
    super.viewDidLoad()
    getData() //Pull last saved time from Core Data and load it.
    hourInput.stringValue = "(hours)" //Loading the hours into the hours field
    minuteInput.stringValue = "(minutes)" //Loading the minutes into the minutes field
    secondInput.stringValue = "(seconds)" //Loading the seconds into the seconds field
    initialTime.stringValue = "00:00:00" //Resetting the 'counter' to 0
    firstRun = true
    updateStatusBar(self)

    //Here we load up the audio file for the 'done' chime. If not available we print the catch
    do
    {
    let audioPath = Bundle.main.path(forResource: "Done", ofType: "m4a")
    try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath!))
    }
    catch
    {
    print("No Joy")
    }
    /* if let button = item.button
    {
    button.image = NSImage(named: NSImage.Name("2"))
    button.title = initialTime.stringValue
    button.action = #selector(togglePopover(_:))
    }
    */ }

    }

    // MARK: Storyboard instantiation

    extension TimerViewController
    {
    static func freshController() -> TimerViewController
    {
    let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil)
    let identifier = NSStoryboard.SceneIdentifier("TimerViewController")
    guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? TimerViewController
    else
    {
    fatalError("Why can't I find TimerViewController? - Check Main.storyboard")
    }
    return viewcontroller
    }
    }

    //Button actions follow

    extension TimerViewController
    {
    @IBAction func clearButton(_ sender: Any)
    {
    clearFields()
    timer.invalidate()
    audioPlayer.stop()
    }

    @IBAction func pauseButton(_ sender: Any)
    {
    timer.invalidate()
    }

    @IBAction func quitButton(_ sender: Any)
    {
    exit(0)
    }

    @IBAction func startButton(_ sender: Any)
    {
    grabData()
    setData()

    timeRemaining = (hours*3600)+(minutes*60)+seconds

    if timeRemaining <= 0
    {
    initialTime.stringValue = "Enter Time"
    }

    else
    {
    displayTime()

    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.startCountDown), userInfo: nil, repeats: true)

    clearFields()
    updateStatusBar(self)
    }
    }
    }

    //MARK: Other Functions

    extension TimerViewController
    {
    func displayTime()
    {
    let secondsDisplay = String(format: "%02d", (timeRemaining%60))
    let minutesDisplay = String(format: "%02d", (timeRemaining%3600)/60)
    initialTime.stringValue = "(timeRemaining/3600):(minutesDisplay):(secondsDisplay)"
    }

    func grabData()
    {
    hours = hourInput.integerValue
    minutes = minuteInput.integerValue
    seconds = secondInput.integerValue
    }

    func clearFields()
    {
    hourInput.stringValue = ""
    minuteInput.stringValue = ""
    secondInput.stringValue = ""
    initialTime.stringValue = "00:00:00"
    }

    func setData()
    {
    setHour()
    setMinute()
    setSecond()
    }

    func getData()
    {
    getHour()
    getMinute()
    getSecond()
    }

    @objc func showTimer(_ sender: Any?)
    {
    print("Are we here")
    }
    @objc func startCountDown()
    {

    timeRemaining -= 1
    displayTime()
    updateStatusBar(self)
    print(timeRemaining)

    if timeRemaining == 0
    {
    timer.invalidate()
    audioPlayer.play()
    }
    }

    /* func setNeedsStatusBarAppearanceUpdate()
    {
    button.image = NSImage(named: NSImage.Name("2"))
    button.action = #selector(showTimer(_:))
    }
    */
    func updateStatusBar(_ sender: Any?)
    {
    if let button = item.button
    {
    button.image = NSImage(named: NSImage.Name("2"))
    button.action = #selector(showTimer(_:))
    button.title = initialTime.stringValue
    }

    //let menu = NSMenu()
    //menu.addItem(NSMenuItem(title: "Clear Timer", action: #selector(AppDelegate.theDv2), keyEquivalent: "R"))
    //menu.addItem(NSMenuItem(title: "Quit Timer", action: #selector(AppDelegate.quit), keyEquivalent: "Q"))
    //item.menu = menu
    }

    }


    //There's a bunch of CoreData stuff after here but I left that out. I'm just using CoreData mainly to learn how to and functional reason is to store and load the last used time



    As it currently works, I get two StatusBar items instead of creating one with the AppDelegate then updating that one from the ViewController.










    share|improve this question

























      0












      0








      0


      1






      I'm trying to create a Countdown Timer application that runs in the Menu Bar, with no window or dock icon. I've been building this off of mostly tutorials I find online and I know the code is kind of messy (I plan to clean up after it functions properly). The issue I'm running into. In the AppDelegate I create the StatusBar item with no issue, but I can't figure out how to update it from the viewController. It instead is creating a new StatusBar item.



      //AppDelegate info



      class AppDelegate: NSObject, NSApplicationDelegate
      {

      let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
      let popover = NSPopover()

      func applicationDidFinishLaunching(_ aNotification: Notification)
      {
      menuBarRefresh(self)
      }

      func menuBarRefresh(_ sender: Any?)
      {
      if let button = item.button
      {
      button.image = NSImage(named: NSImage.Name("2"))
      //button.title = initialTime.stringValue
      button.action = #selector(togglePopover(_:))
      }
      popover.contentViewController = TimerViewController.freshController()
      }

      @objc func togglePopover(_ sender: Any?)
      {
      if popover.isShown
      {
      closePopover(sender: sender)
      }
      else
      {
      showPopover(sender: sender)
      }
      }

      func showPopover(sender: Any?)
      {
      if let button = item.button
      {
      popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
      }
      }

      func closePopover(sender: Any?)
      {
      popover.performClose(sender)
      }


      //Controller code



      import Cocoa
      import AVFoundation

      //Checking to ensure entered data is numeric
      extension String
      {
      var isNumeric: Bool
      {
      let range = self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted)
      return (range == nil)
      }
      }

      class TimerViewController: NSViewController
      {

      //Here's the texts fields for the user to enter content.
      @IBOutlet var hourInput: NSTextField!
      @IBOutlet var minuteInput: NSTextField!
      @IBOutlet var secondInput: NSTextField!

      //This is the label used to display the counter
      @IBOutlet var initialTime: NSTextField!

      //Here are the variables we're going to need
      var hours = Int() //Place holder for the hours
      var minutes = Int() //Place holder for the hours
      var seconds = Int() //Place holder for the hours
      var timer = Timer() //The timer we'll use later
      var audioPlayer = AVAudioPlayer() //The audio player
      var timeRemaining = Int() //Place holder for the total 'seconds' to be counted
      var firstRun = Bool()

      let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

      override func viewDidLoad()
      {
      super.viewDidLoad()
      getData() //Pull last saved time from Core Data and load it.
      hourInput.stringValue = "(hours)" //Loading the hours into the hours field
      minuteInput.stringValue = "(minutes)" //Loading the minutes into the minutes field
      secondInput.stringValue = "(seconds)" //Loading the seconds into the seconds field
      initialTime.stringValue = "00:00:00" //Resetting the 'counter' to 0
      firstRun = true
      updateStatusBar(self)

      //Here we load up the audio file for the 'done' chime. If not available we print the catch
      do
      {
      let audioPath = Bundle.main.path(forResource: "Done", ofType: "m4a")
      try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath!))
      }
      catch
      {
      print("No Joy")
      }
      /* if let button = item.button
      {
      button.image = NSImage(named: NSImage.Name("2"))
      button.title = initialTime.stringValue
      button.action = #selector(togglePopover(_:))
      }
      */ }

      }

      // MARK: Storyboard instantiation

      extension TimerViewController
      {
      static func freshController() -> TimerViewController
      {
      let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil)
      let identifier = NSStoryboard.SceneIdentifier("TimerViewController")
      guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? TimerViewController
      else
      {
      fatalError("Why can't I find TimerViewController? - Check Main.storyboard")
      }
      return viewcontroller
      }
      }

      //Button actions follow

      extension TimerViewController
      {
      @IBAction func clearButton(_ sender: Any)
      {
      clearFields()
      timer.invalidate()
      audioPlayer.stop()
      }

      @IBAction func pauseButton(_ sender: Any)
      {
      timer.invalidate()
      }

      @IBAction func quitButton(_ sender: Any)
      {
      exit(0)
      }

      @IBAction func startButton(_ sender: Any)
      {
      grabData()
      setData()

      timeRemaining = (hours*3600)+(minutes*60)+seconds

      if timeRemaining <= 0
      {
      initialTime.stringValue = "Enter Time"
      }

      else
      {
      displayTime()

      timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.startCountDown), userInfo: nil, repeats: true)

      clearFields()
      updateStatusBar(self)
      }
      }
      }

      //MARK: Other Functions

      extension TimerViewController
      {
      func displayTime()
      {
      let secondsDisplay = String(format: "%02d", (timeRemaining%60))
      let minutesDisplay = String(format: "%02d", (timeRemaining%3600)/60)
      initialTime.stringValue = "(timeRemaining/3600):(minutesDisplay):(secondsDisplay)"
      }

      func grabData()
      {
      hours = hourInput.integerValue
      minutes = minuteInput.integerValue
      seconds = secondInput.integerValue
      }

      func clearFields()
      {
      hourInput.stringValue = ""
      minuteInput.stringValue = ""
      secondInput.stringValue = ""
      initialTime.stringValue = "00:00:00"
      }

      func setData()
      {
      setHour()
      setMinute()
      setSecond()
      }

      func getData()
      {
      getHour()
      getMinute()
      getSecond()
      }

      @objc func showTimer(_ sender: Any?)
      {
      print("Are we here")
      }
      @objc func startCountDown()
      {

      timeRemaining -= 1
      displayTime()
      updateStatusBar(self)
      print(timeRemaining)

      if timeRemaining == 0
      {
      timer.invalidate()
      audioPlayer.play()
      }
      }

      /* func setNeedsStatusBarAppearanceUpdate()
      {
      button.image = NSImage(named: NSImage.Name("2"))
      button.action = #selector(showTimer(_:))
      }
      */
      func updateStatusBar(_ sender: Any?)
      {
      if let button = item.button
      {
      button.image = NSImage(named: NSImage.Name("2"))
      button.action = #selector(showTimer(_:))
      button.title = initialTime.stringValue
      }

      //let menu = NSMenu()
      //menu.addItem(NSMenuItem(title: "Clear Timer", action: #selector(AppDelegate.theDv2), keyEquivalent: "R"))
      //menu.addItem(NSMenuItem(title: "Quit Timer", action: #selector(AppDelegate.quit), keyEquivalent: "Q"))
      //item.menu = menu
      }

      }


      //There's a bunch of CoreData stuff after here but I left that out. I'm just using CoreData mainly to learn how to and functional reason is to store and load the last used time



      As it currently works, I get two StatusBar items instead of creating one with the AppDelegate then updating that one from the ViewController.










      share|improve this question














      I'm trying to create a Countdown Timer application that runs in the Menu Bar, with no window or dock icon. I've been building this off of mostly tutorials I find online and I know the code is kind of messy (I plan to clean up after it functions properly). The issue I'm running into. In the AppDelegate I create the StatusBar item with no issue, but I can't figure out how to update it from the viewController. It instead is creating a new StatusBar item.



      //AppDelegate info



      class AppDelegate: NSObject, NSApplicationDelegate
      {

      let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
      let popover = NSPopover()

      func applicationDidFinishLaunching(_ aNotification: Notification)
      {
      menuBarRefresh(self)
      }

      func menuBarRefresh(_ sender: Any?)
      {
      if let button = item.button
      {
      button.image = NSImage(named: NSImage.Name("2"))
      //button.title = initialTime.stringValue
      button.action = #selector(togglePopover(_:))
      }
      popover.contentViewController = TimerViewController.freshController()
      }

      @objc func togglePopover(_ sender: Any?)
      {
      if popover.isShown
      {
      closePopover(sender: sender)
      }
      else
      {
      showPopover(sender: sender)
      }
      }

      func showPopover(sender: Any?)
      {
      if let button = item.button
      {
      popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
      }
      }

      func closePopover(sender: Any?)
      {
      popover.performClose(sender)
      }


      //Controller code



      import Cocoa
      import AVFoundation

      //Checking to ensure entered data is numeric
      extension String
      {
      var isNumeric: Bool
      {
      let range = self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted)
      return (range == nil)
      }
      }

      class TimerViewController: NSViewController
      {

      //Here's the texts fields for the user to enter content.
      @IBOutlet var hourInput: NSTextField!
      @IBOutlet var minuteInput: NSTextField!
      @IBOutlet var secondInput: NSTextField!

      //This is the label used to display the counter
      @IBOutlet var initialTime: NSTextField!

      //Here are the variables we're going to need
      var hours = Int() //Place holder for the hours
      var minutes = Int() //Place holder for the hours
      var seconds = Int() //Place holder for the hours
      var timer = Timer() //The timer we'll use later
      var audioPlayer = AVAudioPlayer() //The audio player
      var timeRemaining = Int() //Place holder for the total 'seconds' to be counted
      var firstRun = Bool()

      let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

      override func viewDidLoad()
      {
      super.viewDidLoad()
      getData() //Pull last saved time from Core Data and load it.
      hourInput.stringValue = "(hours)" //Loading the hours into the hours field
      minuteInput.stringValue = "(minutes)" //Loading the minutes into the minutes field
      secondInput.stringValue = "(seconds)" //Loading the seconds into the seconds field
      initialTime.stringValue = "00:00:00" //Resetting the 'counter' to 0
      firstRun = true
      updateStatusBar(self)

      //Here we load up the audio file for the 'done' chime. If not available we print the catch
      do
      {
      let audioPath = Bundle.main.path(forResource: "Done", ofType: "m4a")
      try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: audioPath!))
      }
      catch
      {
      print("No Joy")
      }
      /* if let button = item.button
      {
      button.image = NSImage(named: NSImage.Name("2"))
      button.title = initialTime.stringValue
      button.action = #selector(togglePopover(_:))
      }
      */ }

      }

      // MARK: Storyboard instantiation

      extension TimerViewController
      {
      static func freshController() -> TimerViewController
      {
      let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil)
      let identifier = NSStoryboard.SceneIdentifier("TimerViewController")
      guard let viewcontroller = storyboard.instantiateController(withIdentifier: identifier) as? TimerViewController
      else
      {
      fatalError("Why can't I find TimerViewController? - Check Main.storyboard")
      }
      return viewcontroller
      }
      }

      //Button actions follow

      extension TimerViewController
      {
      @IBAction func clearButton(_ sender: Any)
      {
      clearFields()
      timer.invalidate()
      audioPlayer.stop()
      }

      @IBAction func pauseButton(_ sender: Any)
      {
      timer.invalidate()
      }

      @IBAction func quitButton(_ sender: Any)
      {
      exit(0)
      }

      @IBAction func startButton(_ sender: Any)
      {
      grabData()
      setData()

      timeRemaining = (hours*3600)+(minutes*60)+seconds

      if timeRemaining <= 0
      {
      initialTime.stringValue = "Enter Time"
      }

      else
      {
      displayTime()

      timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.startCountDown), userInfo: nil, repeats: true)

      clearFields()
      updateStatusBar(self)
      }
      }
      }

      //MARK: Other Functions

      extension TimerViewController
      {
      func displayTime()
      {
      let secondsDisplay = String(format: "%02d", (timeRemaining%60))
      let minutesDisplay = String(format: "%02d", (timeRemaining%3600)/60)
      initialTime.stringValue = "(timeRemaining/3600):(minutesDisplay):(secondsDisplay)"
      }

      func grabData()
      {
      hours = hourInput.integerValue
      minutes = minuteInput.integerValue
      seconds = secondInput.integerValue
      }

      func clearFields()
      {
      hourInput.stringValue = ""
      minuteInput.stringValue = ""
      secondInput.stringValue = ""
      initialTime.stringValue = "00:00:00"
      }

      func setData()
      {
      setHour()
      setMinute()
      setSecond()
      }

      func getData()
      {
      getHour()
      getMinute()
      getSecond()
      }

      @objc func showTimer(_ sender: Any?)
      {
      print("Are we here")
      }
      @objc func startCountDown()
      {

      timeRemaining -= 1
      displayTime()
      updateStatusBar(self)
      print(timeRemaining)

      if timeRemaining == 0
      {
      timer.invalidate()
      audioPlayer.play()
      }
      }

      /* func setNeedsStatusBarAppearanceUpdate()
      {
      button.image = NSImage(named: NSImage.Name("2"))
      button.action = #selector(showTimer(_:))
      }
      */
      func updateStatusBar(_ sender: Any?)
      {
      if let button = item.button
      {
      button.image = NSImage(named: NSImage.Name("2"))
      button.action = #selector(showTimer(_:))
      button.title = initialTime.stringValue
      }

      //let menu = NSMenu()
      //menu.addItem(NSMenuItem(title: "Clear Timer", action: #selector(AppDelegate.theDv2), keyEquivalent: "R"))
      //menu.addItem(NSMenuItem(title: "Quit Timer", action: #selector(AppDelegate.quit), keyEquivalent: "Q"))
      //item.menu = menu
      }

      }


      //There's a bunch of CoreData stuff after here but I left that out. I'm just using CoreData mainly to learn how to and functional reason is to store and load the last used time



      As it currently works, I get two StatusBar items instead of creating one with the AppDelegate then updating that one from the ViewController.







      macos swift4 appdelegate nsviewcontroller nsstatusitem






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 1 at 11:17









      ZardozZardoz

      33




      33
























          1 Answer
          1






          active

          oldest

          votes


















          0














          Yup... Id-10-t error here. Just had to declare 'item' outside the class and all is well. After getting some good sleep and time away from the computer I realized I was not declaring 'item' globally.






          share|improve this answer























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53994995%2fhow-to-update-a-status-item-created-by-appdelegate-from-nsviewcontroller%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            Yup... Id-10-t error here. Just had to declare 'item' outside the class and all is well. After getting some good sleep and time away from the computer I realized I was not declaring 'item' globally.






            share|improve this answer




























              0














              Yup... Id-10-t error here. Just had to declare 'item' outside the class and all is well. After getting some good sleep and time away from the computer I realized I was not declaring 'item' globally.






              share|improve this answer


























                0












                0








                0







                Yup... Id-10-t error here. Just had to declare 'item' outside the class and all is well. After getting some good sleep and time away from the computer I realized I was not declaring 'item' globally.






                share|improve this answer













                Yup... Id-10-t error here. Just had to declare 'item' outside the class and all is well. After getting some good sleep and time away from the computer I realized I was not declaring 'item' globally.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Jan 2 at 12:31









                ZardozZardoz

                33




                33
































                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53994995%2fhow-to-update-a-status-item-created-by-appdelegate-from-nsviewcontroller%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    MongoDB - Not Authorized To Execute Command

                    How to fix TextFormField cause rebuild widget in Flutter

                    Npm cannot find a required file even through it is in the searched directory