Search code examples
swiftmacoscocoanotificationcenternsworkspace

Listening for NSWorkspace Notifications in Swift 4


The simple Swift 4 example below should stop when the computer's display goes to sleep.

class Observer {
    var asleep = false

    func addDNC () {
        NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.screensDidSleepNotification, object: nil, queue: nil, using: notificationRecieved)
    }

    func notificationRecieved (n: Notification) {
        asleep = true
    }
}

let observer = Observer ()
observer.addDNC ()

while (!observer.asleep) {}
print ("zzzz")

However, the program gets stuck in the while loop. What am I doing wrong, and what is the proper way to wait for a Notification?

I have tried using a selector (#selector (notificationRecieved), with @objc in the function declaration, of course), to no avail.


Solution

  • Start a template app in Xcode and modify the ViewController.swift to do this:

    import Cocoa
    
    class Observer {
        var asleep = false
    
        func addDNC () {
            NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.screensDidSleepNotification, object: nil, queue: nil, using: notificationRecieved)
        }
    
        func notificationRecieved (n: Notification) {
            print("got sleep notification!")
            asleep = true
        }
    }
    
    class ViewController: NSViewController {
    
        let observer = Observer ()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // Do any additional setup after loading the view.
    
            observer.addDNC ()
        }
    
        override var representedObject: Any? {
            didSet {
            // Update the view, if already loaded.
            }
        }
    
    
    }
    

    The difference between your code and mine is that I'm not doing the wacky sleepy polling thing you're doing (that's going to lead to a spinning pizza cursor), and I'm also setting observer to be a property off the ViewController object, so the observer property sticks around as long as the view controller does.