objective-cnsrunningapplication

Objective-C: Refreshing FrontmostApplication


I wrote this little program which is supposed to print the current frontmost application twice, with a 3-second break in between.

void printFrontmostApp() {
    NSRunningApplication *frontmostApplication = [NSWorkspace sharedWorkspace].frontmostApplication;
    NSLog(@"%@",frontmostApplication);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        printFrontmostApp();
        sleep(3);
        printFrontmostApp();
    }
    return 0;
}

When I ran this program, I realised that frontmostApplication is not refreshed when it is called the second time. I found the solution here. But I still have two questions:

1) I want to know why the frontmostApplication is not updated.

2) How do I force it to refresh every time I call it? I don't want to receive a notification every time the frontmost application deactivates, because it is a little inefficient for my purposes.

Edit: Just to be crystal clear, let's suppose the time now is 10:00:00. I call printFrontmostApp, and it prints "Xcode" to the console, because Xcode is the current frontmost app. Then the program sleeps for 3 seconds. At 10:00:01, I opened another app, say TextEdit. At 10:00:03, my program calls printFrontmostApp for the second time. I expect it to print "TextEdit", which is the current frontmost application. But it prints "Xcode" instead. I can't understand this behaviour.

Can someone please explain what happens at 10:00:03? The function seems to "remember" the value of frontmostApplication at 10:00:00 and retains it when it is called the second time. I thought that any memory will be released once it goes out of scope, so why is this happening?

And how do I get my program to get the frontmost app at 10:00:03? I can get the frontmost app at 10:00:00, I should be able to do the same 3 seconds later right?


Solution

  • The documentation for -[NSWorkspace runningApplications] — not the method you're using, but related — says:

    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.

    From the NSRunningApplication documentation:

    Properties that vary over time are inherently race-prone. For example, a hidden app may unhide itself at any time. To ameliorate this, properties persist until the next turn of the main run loop in a common mode. For example, if you repeatedly poll an unhidden app for its hidden property without allowing the run loop to run, it will continue to return NO, even if the app hides, until the next turn of the run loop.

    It's a near certainty that the same principle applies to -frontmostApplication even though the documentation doesn't say so explicitly. You will never get different results by polling without allowing the run loop to run.