您的问题与块(或字典)无关,与您 (ab) 使用的方式有关-runningApplications
。从文档:
类似于 NSRunningApplication 类的属性,这个属性只有在主运行循环以普通模式运行时才会改变。使用键值观察来通知此数组属性的更改,而不是轮询。
为此,以下演示了正确的行为:
#import "AppDelegate.h"
const static NSString *runningApplicationsContext = @"running applications observation";
@implementation AppDelegate
@synthesize window = _window;
- (void)dealloc
{
[[NSWorkspace sharedWorkspace] removeObserver:self
forKeyPath:@"runningApplications"
context:&runningApplicationsContext];
[super dealloc];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[NSWorkspace sharedWorkspace] addObserver:self
forKeyPath:@"runningApplications"
options:NSKeyValueObservingOptionNew
context:&runningApplicationsContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == &runningApplicationsContext) {
NSArray *runningApps = [(NSWorkspace *)object runningApplications];
NSMutableArray *appNames = [[NSMutableArray alloc] initWithCapacity:[runningApps count]];
for (NSRunningApplication *app in runningApps) {
[appNames addObject:[app localizedName]];
}
NSLog(@"%@", [[NSWorkspace sharedWorkspace] runningApplications]);
[appNames release];
}
}
这还有另一个好处:您可以检查change
字典以确定哪些应用程序触发了通知,以防您感兴趣。这使您免于缓存/跟踪以前的runningApplications
结果。
编辑:跟进您的评论,这里有一些代码可以很好地与您的块(剥离了我认为在您的较大应用程序中执行某些操作的死代码)存储在字典中并从观察者方法调用:
#import "AppDelegate.h"
const static NSString *runningApplicationsContext = @"running applications observation";
@interface AppDelegate () {
NSDictionary *_blocks;
}
@end
@implementation AppDelegate
@synthesize window = _window;
- (void)dealloc
{
[[NSWorkspace sharedWorkspace] removeObserver:self
forKeyPath:@"runningApplications"
context:&runningApplicationsContext];
[_blocks release];
[super dealloc];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
_blocks = [[NSDictionary alloc] initWithObjectsAndKeys:(id)
^{
NSLog(@"%@", [[NSWorkspace sharedWorkspace] runningApplications]);
}, @"RunningApplications",
nil];
[[NSWorkspace sharedWorkspace] addObserver:self
forKeyPath:@"runningApplications"
options:NSKeyValueObservingOptionNew
context:&runningApplicationsContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == &runningApplicationsContext) {
dispatch_block_t getRunningApplications = [_blocks objectForKey:@"RunningApplications"];
getRunningApplications();
}
}
@end