Objective c 什么是';正确的';在OSX 10.6+;中识别当前活动应用程序的方法;?
我正在尝试确定哪个OSX应用程序当前处于活动状态。我知道在OSX 10.5中,这可以通过以下方式实现:Objective c 什么是';正确的';在OSX 10.6+;中识别当前活动应用程序的方法;?,objective-c,cocoa,Objective C,Cocoa,我正在尝试确定哪个OSX应用程序当前处于活动状态。我知道在OSX 10.5中,这可以通过以下方式实现: [[NSWorkspace sharedWorkspace] activeApplication] 然而,这在10.6+中已被弃用 apple developers文档指出,这应该通过NSRunningApplication对象的“active”属性来完成。我认为实现这一点的一种方法可能是获得所有正在运行的应用程序的列表 [[NSWorkspace sharedWorkspace] runn
[[NSWorkspace sharedWorkspace] activeApplication]
然而,这在10.6+中已被弃用
apple developers文档指出,这应该通过NSRunningApplication对象的“active”属性来完成。我认为实现这一点的一种方法可能是获得所有正在运行的应用程序的列表
[[NSWorkspace sharedWorkspace] runningApplications]
然后循环,检查每个应用程序的“活动”属性。但是,以下测试代码的行为与我预期的不同:当从Terminal.app编译和运行时,无论我是否选择其他应用程序,只有“Terminal”应用程序始终标记为活动
#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;
}
#导入
#进口
#进口
int main(int argc,char*argv[]){
而(1){
NSAutoreleasePool*池=[[NSAutoreleasePool alloc]init];
NSString*currApp;
NSArray*运行应用程序;
runningApps=[[NSWorkspace sharedWorkspace]runningApplications];
用于(运行应用程序中的id currApp){
如果([currApp isActive])
NSLog(@“*%@,[currApp localizedName]);
其他的
NSLog(@“%@,[currApp localizedName]);
}
睡眠(1);
[池释放];
}
返回0;
}
我做错了什么?我是否误解了“主动”属性的工作原理
(另外,请随意批评我的Objective C代码——这是我第一次尝试Objective C,所以我知道它对训练有素的人来说可能会非常难看!请原谅我!:)欢迎任何建议。)NSWorkspace的注释如下: 特殊注意事项 强烈建议您使用NSRunningApplication 班级 或activemethods在目标应用程序中检索此信息 适用于Mac OS X v10.6及更高版本 您可能应该在那里执行一组10.6及更新的代码和一组10.5.X及更旧的代码 B.T.W.,从10.7开始,NSWorkspace方法仅被标记为不推荐使用,但NSRunningApplication从10.6开始使用 哦,如果包括应用程序服务框架,这里有一个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;
}
每隔一秒钟左右轮询一次以发现当前应用程序效率低下,这是错误的做法。一种更好的方法是简单地设置流程以接收通知
@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;
}
@接口MDAppController:NSObject{
NSRunningApplication*currentApp;
}
@属性(保留)NSRunningApplication*currentApp;
@结束
@MDAppController的实现
@合成currentApp;
-(id)init{
if((self=[super init])){
[[[NSWorkspace sharedWorkspace]通知中心]添加观察者:self
选择器:@selector(activeAppDidChange:)
名称:NSWorkspaceDidActivateApplicationNotification对象:nil];
}
回归自我;
}
-(无效)解除锁定{
[[[NSWorkspace sharedWorkspace]通知中心]removeObserver:self];
[super dealoc];
}
-(无效)activeAppDidChange:(NSNotification*)通知{
self.currentApp=[[notification userInfo]objectForKey:NSWorkspaceApplicationKey];
NSLog(@“currentApp=%@”,currentApp);
}
@结束
int main(int argc,const char*argv[]{
NSAutoreleasePool*池=[[NSAutoreleasePool alloc]init];
[NSApplication sharedApplication];
MDAppController*appController=[[MDAppController alloc]init];
[NSApp setDelegate:appController];
[NSApp运行];
[池释放];
返回0;
}
您的问题是,您的应用程序无法从系统接收任何通知当前应用程序已更改的事件,因此它从不更新NSRunningApplication
实例上的活动属性。如果我使用完全相同的代码,但当我开始运行代码时另一个应用程序处于活动状态,它会报告该应用程序
相反,如果您更改代码以运行主线程的nsrunlop
,并使用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];
}
#导入
#进口
@接口Foo:NSObject
-(无效)运行;
@结束
@执行Foo
-(无效)运行{
对于(NSRunningApplication*currApp在[[NSWorkspace sharedWorkspace]运行应用程序]中){
如果([currApp isActive]){
NSLog(@“*%@,[currApp localizedName]);
}否则{
NSLog(@“%@,[currApp localizedName]);
}
}
NSLog(@“--”);
}
@结束
int main(int argc,char*argv[]){
NSAutoreleasePool*p=[NSAutoreleasePool新建];
Foo*Foo=[[Foo新]自动释放];
NSTimer*定时器=[NSTimer scheduledTimerWithTimeInterval:1.0f
目标:富
选择器:@selector(运行)
用户信息:无
重复:是];
[[nsrunlop main runloop]run];
[p释放];
}
从OS X 10.7开始,NSWorkspace也有方便的方法:
- (NSRunningApplication *)frontmostApplication;
此外,您现在还可以使用Grand Central dispatch调用来进行超时的重复调用
大概是这样的:
- (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
});
}
嗨,迈克尔,谢谢你的回复。我确实尝试过使用“currentApplication”,但这会返回调用的应用程序(即,在我的例子中,本地化名称为“null”,因为我正在运行命令行进程)。我想避免使用activeApplication的原因正是您建议的,即它已被弃用。然而,使用“主动”似乎不起作用;我实际上是在10.6上编码,ownsMenuBar是10.7。但是谢谢你的建议。使用
NSRunningApplication.current
我相信currentApplication
会返回表示运行代码的应用程序的NSRunningApplication
,而不是UI中最重要的应用程序。嗨,天哪,我尝试过了
- (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]);
}