4

I want to display a list of all running application names.

Issue: It doesn't add an app that is running after the function is called. Therefore, it doesn't add the app name to the list simultaneously.

Goal: I want to add a listener, so if a new app is running it will add it to the array simultaneously without restarting the app or recalling the function again.

func allRunningApplications() {

        for runningApplication in NSWorkspace.shared.runningApplications {

            let appName = runningApplication.localizedName

            // Add App Name to Array
            array.append(appName)
    }
}
dbrownjave
  • 437
  • 1
  • 8
  • 19

3 Answers3

6

I mentioned the "did launch", et. al., notifications because you didn't explain why you wanted to monitor the set of running applications.

If you are only interested in whether a specific app has launched (or quit), it would probably be easier to use the NSWorkspace notifications:

(untested code)

let center = NSWorkspace.shared.notificationCenter
center.addObserver(forName: NSWorkspace.didLaunchApplicationNotification,
                    object: nil, // always NSWorkspace
                     queue: OperationQueue.main) { (notification: Notification) in
                        if let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication {
                            if app.bundleIdentifier == "com.apple.Terminal" {
                                // User just launched the Terminal app; should we be worried?
                            }
                        }
}

Note that workspace notifications are posted to NSWorkspace's private notification center, not the default notification center, so remember to add your observers there.

James Bucanek
  • 3,299
  • 3
  • 14
  • 30
5

You could poll the runningApplications property (check it every x seconds) to test, if there is a new application. But it's not recommended: https://developer.apple.com/documentation/appkit/nsworkspace/1534059-runningapplications

Similar to the NSRunningApplication class’s properties, this property will only change when the main run loop is run in a common mode. Instead of polling, use key-value observing to be notified of changes to this array property.

So use key-value observing on NSWorkspace.shared.runningApplications

A good example can be found here: https://www.ralfebert.de/ios-examples/swift/property-key-value-observer/

For your code it should be something like this:

var observers = [NSKeyValueObservation]()

override func viewDidLoad() {
    super.viewDidLoad()

    observeModel()
}

func observeModel() {
    self.observers = [
        NSWorkspace.shared.observe(\.NSWorkspace.runningApplications, options: [.initial]) {(model, change) in
            // runningApplications changed, so update your UI or something else
        }
    ]
}

(untested code)

Business Tomcat
  • 1,021
  • 9
  • 12
  • 2
    It probably should be `NSWorkspace.shared.observe(\.runningApplications, ...)` – Martin R Mar 03 '18 at 16:08
  • @MartinR You're right, thanks! I updated the answer, but let the full keypath of runningApplications. – Business Tomcat Mar 03 '18 at 16:17
  • Just FYI, there are also the `NSWorkspaceDidTerminateApplicationNotification` and `NSWorkspaceDidLaunchApplicationNotification` notifications. – James Bucanek Mar 03 '18 at 16:47
  • @JamesBucanek can you please provide an example using NSWorkspaceDidLaunchApplicationNotification ? – dbrownjave Mar 05 '18 at 05:49
  • 1
    Note that you should **not** poll the `runningApplications` method. The docs specifically state: `Similar to the NSRunningApplication class’s properties, this property will only change when the main run loop is run in a common mode. Instead of polling, use key-value observing to be notified of changes to this array property.` – Patrick Jun 27 '22 at 23:21
2

You can try using the notification centre of NSWorkspace.

    self.workspace = [NSWorkspace new];
    NSArray *myObserver;
    myObserver = (NSArray*) [[[NSWorkspace sharedWorkspace] notificationCenter] addObserverForName:  NSWorkspaceWillLaunchApplicationNotification object:nil queue:nil usingBlock:^(NSNotification *note)
                         {
                             if(note)
                             {
                               //do your action
                             }
                         }
                        ];

NSWorkspaceWillLaunchApplicationNotification will notify you if any application is about to be launched.

Bharath Suresh
  • 483
  • 2
  • 18