如何让我的块更新?

时间:2012-04-17 01:46:31

标签: cocoa block

我将块存储在NSDictionary中。这是其中一个块:

void(^RunningApplications)(void) = ^{
        NSArray *runningApps = [[NSWorkspace sharedWorkspace] runningApplications];
        NSMutableArray *appNames = [[NSMutableArray alloc] initWithCapacity:[runningApps count]];
        for (NSRunningApplication *app in runningApps)
            [appNames addObject:[app localizedName]];
        NSLog(@"%@", [[NSWorkspace sharedWorkspace] runningApplications]);
    };

我第一次访问此块时,会看到当前正在运行NSLog的应用。但是,如果我打开另一个应用程序,然后再次调用该块,我只会看到显示的原始列表,而不是新打开的应用程序的新列表。如何通过此块接收更新列表?

1 个答案:

答案 0 :(得分:3)

您的问题与块(或词典)无关,也与您使用-runningApplications的方式无关。来自docs

  

与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