我正在尝试确定哪个OSX应用程序当前处于活动状态。据我所知,在OSX 10.5中,可以通过以下方式完成:
[[NSWorkspace sharedWorkspace] activeApplication]
但是,这已在10.6 +中弃用。
apple developers文档指出,这应该通过NSRunningApplication对象的“active”属性来完成。我认为解决这个问题的一种方法可能是通过
获取所有正在运行的应用程序的列表[[NSWorkspace sharedWorkspace] runningApplications]
然后循环,检查每个应用程序的“active”属性。但是,以下测试代码的行为与我的预期不同:从Terminal.app编译和运行时,无论是否选择其他应用程序,只有“终端”应用程序被标记为活动状态。
#import <Foundation/Foundation.h>
#import <AppKit/NSRunningApplication.h>
#import <AppKit/NSWorkspace.h>
int main(int argc, char *argv[]) {
while(1){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *currApp;
NSArray *runningApps;
runningApps = [[NSWorkspace sharedWorkspace] runningApplications];
for (id currApp in runningApps) {
if ([currApp isActive])
NSLog(@"* %@", [currApp localizedName]);
else
NSLog(@" %@", [currApp localizedName]);
}
sleep(1);
[pool release];
}
return 0;
}
我做错了什么?我误解了“主动”财产的运作方式吗?
(另外,请随意批评我的Objective C代码---这是我在目标C上的第一次尝试,所以我知道它可能会让受过训练的眼睛难看!请原谅我!:)欢迎任何建议。)
答案 0 :(得分:18)
您的问题是您的应用程序无法从系统接收任何事件,通知它当前应用程序已更改,因此它永远不会更新NSRunningApplication
实例上的活动属性。如果我使用完全相同的代码,但是当我开始运行代码时,另一个应用程序处于活动状态,则会报告该应用程序。
如果您更改代码以运行主线程的NSRunLoop
并使用1秒计时器,它应该可以工作。
这是一个简单的例子:
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
@interface Foo : NSObject
- (void)run;
@end
@implementation Foo
- (void)run {
for (NSRunningApplication *currApp in [[NSWorkspace sharedWorkspace] runningApplications]) {
if ([currApp isActive]) {
NSLog(@"* %@", [currApp localizedName]);
} else {
NSLog(@" %@", [currApp localizedName]);
}
}
NSLog(@"---");
}
@end
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [NSAutoreleasePool new];
Foo *foo = [[Foo new] autorelease];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:foo
selector:@selector(run)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] run];
[p release];
}
答案 1 :(得分:17)
每隔一秒左右进行轮询以找出当前的应用程序是低效的,并且这是错误的方法。更好的方法是简单地设置您的流程以接收NSWorkspaceDidActivateApplicationNotification
通知。
@interface MDAppController : NSObject <NSApplicationDelegate> {
NSRunningApplication *currentApp;
}
@property (retain) NSRunningApplication *currentApp;
@end
@implementation MDAppController
@synthesize currentApp;
- (id)init {
if ((self = [super init])) {
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:@selector(activeAppDidChange:)
name:NSWorkspaceDidActivateApplicationNotification object:nil];
}
return self;
}
- (void)dealloc {
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
[super dealloc];
}
- (void)activeAppDidChange:(NSNotification *)notification {
self.currentApp = [[notification userInfo] objectForKey:NSWorkspaceApplicationKey];
NSLog(@"currentApp == %@", currentApp);
}
@end
int main(int argc, const char * argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSApplication sharedApplication];
MDAppController *appController = [[MDAppController alloc] init];
[NSApp setDelegate:appController];
[NSApp run];
[pool release];
return 0;
}
答案 2 :(得分:12)
从OS X 10.7开始NSWorkspace
也有方便的方法:
- (NSRunningApplication *)frontmostApplication;
此外,您现在可以使用Grand Central调度调用来进行重复调用。
这样的事情:
- (void) checkFrontmostApp {
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
NSRunningApplication* runningApp = [[NSWorkspace sharedWorkspace] frontmostApplication];
//do something
NSLog(@"frontmost app: %@", runningApp.bundleIdentifier);
[self checkFrontmostApp]; //'recursive' call
});
}
答案 3 :(得分:1)
NSWorkspace的activeApplication
注释说:
特别注意事项
强烈建议您使用NSRunningApplication 班
currentApplication
或activeMthods在目标应用程序中检索此信息 适用于Mac OS X v10.6及更高版本。
你应该做10.6&amp;更新的代码集和10.5.X及更旧的代码集。
B.T.W。,从10.7开始,NSWorkspace方法仅被标记为已弃用,但NSRunningApplication从10.6开始提供。
哦,如果您包含Application Services框架,这里有64位兼容的替代方案:
int main (int argc, const char * argv[])
{
// insert code here...
CFShow(CFSTR("Hello, World!\n"));
ProcessSerialNumber psn;
OSErr err = GetFrontProcess(&psn);
if(err == noErr)
{
ProcessInfoRec info;
StringPtr processName = malloc(64);
if(processName)
{
bzero(processName, 64);
info.processInfoLength = sizeof(ProcessInfoRec);
info.processName = processName;
err = GetProcessInformation( &psn, &info);
if(err == noErr)
{
fprintf(stdout, "front most process name is %s", processName+1 );
}
free(processName);
}
}
return 0;
}
答案 4 :(得分:0)
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSNotificationCenter *allApplicationsNotificationCenter;
allApplicationsNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
[allApplicationsNotificationCenter addObserver:self selector:@selector(applicationActivated:) name:NSWorkspaceDidActivateApplicationNotification object:nil];
}
- (void)applicationActivated:(NSNotification *)aNotification {
NSLog(@"%@",[[[NSWorkspace sharedWorkspace] menuBarOwningApplication] localizedName]);
}