如何收集多个openFile:(NSString *)事件然后对它们执行某些操作?

时间:2012-01-18 21:42:08

标签: macos cocoa

我正在使用Cocoa / Objective C ++实用程序,并希望处理多个(即时)文件打开。要处理文件打开部分,我在AppDelegate.mm文件中有这个功能:

- (BOOL)application:(NSApplication*)app openFile:(NSString *)filename
{
    NSLog(@"Opening file %@", filename);

    // more C++ code here

    return YES;
}

这些文件正被发送到Quicksilver,我相信这些文件将一个接一个地发送到应用程序(Finder'' Open With"我认为一次发送所有文件 - 所以可能使用handleOpenApplicationEvent:(NSAppleEventDescriptor *)event可能会更好地工作) - 但无论如何,应用程序将一个接一个地接收几个文件 - 几乎是瞬间 - 但不完全在一起。以下是Console.app显示的内容:

console-screenshot.png http://img109.imageshack.us/img109/1205/consolescreenshot.png

由于文件是单独发送的,但是一个接一个地发送,我的问题是如何收集所有发送的文件并对它们做一件事?例如,我想收集所有发送的文件路径,然后在对话框中一起显示它们。

我可以想到一个可能有用的概念:在收到数据时将每个文件路径存储在数组中。同时,当收到第一个时,在后台设置1-2秒的延迟,然后有一个对话框显示特定变量的所有内容。这个概念是正确的还是有更好的方法来做到这一点?我是Cocoa / Objective C ++的新手 - 来自PHP / Perl,bash等语言。

我也希望这个帮助应用程序在完成后终止,但是如果我在等待文件,那么在收到最后一个文件时如何终止应用程序呢?

如果我将[NSApp terminate:nil];添加到applicationDidFinishLaunching函数,则只有收到第一个文件后,应用程序才会终止。

更新 - 更多备注

这是使用openFiles(复数)函数后的控制台: Picture 7.png http://img24.imageshack.us/img24/5715/picture7zc.png

使用Quicksilver,我会抓取一些文件,比如temp目录中的文件,然后选择" Open With"然后我创建的应用程序(名为darn.app)

Screen Shot 2012-01-18 at 7.02.45 PM.png http://img9.imageshack.us/img9/4171/screenshot20120118at702.png

但是使用Finder似乎工作正常:

Screen Shot 2012-01-18 at 7.09.08 PM.png http://img832.imageshack.us/img832/8858/screenshot20120118at709.png

...导致consolea.app:

Picture 8.png http://img24.imageshack.us/img24/2812/picture8fe.png

我确实问过Quicksilver的开发人员,他们确认QS确实打开一个文件,一次打开文件,他们承认这与Finder的做法不同,但他们认为这是预期的。也许Darren是对的 - 计时器可能是最好的方式......

3 个答案:

答案 0 :(得分:5)

尝试实施-application:openFiles:而不是-application:openFile:

- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames
{
    NSLog(@"Opening multiple files %@", filenames);
}

处理从Finder接收多个文件。

如果这对你的Quicksilver设置不起作用,那么计时器可能是最好的方法。

在AppDelegate的-init方法中设置计时器。

@implementation MyAppDelegate {
    NSMutableArray* _files;
}

- (id)init {
    if (self = [super init]) {
        _files = [[NSMutableArray alloc] initWithCapacity:10];

        [self performSelector:@selector(processFiles) 
                   withObject:nil 
                   afterDelay:1.0]; // one second delay
    }
    return self;
}

In -application:openFile:收集数组中的文件并重置计时器。

- (BOOL)application:(NSApplication*)app openFile:(NSString*)filename {
    NSAssert(_files != nil, @"Timer already fired");

    [_files addObject:filename];

    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    [self performSelector:@selector(processFiles) 
               withObject:nil 
               afterDelay:1.0];
} 

当计时器触发时,处理收集的文件,然后退出应用程序。

-(void)processFiles

    // Process the _files

    [_files release];
    _files = nil;
    [NSApp terminate:nil];
}

答案 1 :(得分:1)

系统无法知道是否有更多的文件打开请求,所以不仅没有提供表示最后一个请求的方法,也没有可能的方法。

作为第一个问题的计时器的替代方案,您可以立即开始处理文件并在对话框中显示每个文件,这样用户就会看到列表增长。这不解决第二个问题(在收到所有文件后终止应用程序)。

如果您使用计时器,请确保在每个application:openFile:之后重置计时器。

答案 2 :(得分:0)

我正在使用多个命令行参数启动App可执行文件。

MyApp.app/Contents/MacOS/MyApp file1 file2 file3

每个参数都会生成一个单独的应用程序:openFile(s)调用,如上所述。但是,在这种情况下,在所有openFile调用之后才调用applicationDidFinishLaunching,因此很容易做到这样的事情:

NSMutableArray *_allFiles = nil;

- (void)applicationDidFinishLaunching:(NSNotification *)notification {
  [self handleFiles:_allFiles];
}

- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename {
  [self application:theApplication openFiles:[NSArray arrayWithObject:filename]];
  return YES;
}

- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames {
  if(!_allFiles) _allFiles = [NSMutableArray arrayWithCapacity:8];
  [_allFiles addObjectsFromArray:filenames];
}

此方法也适用于使用"打开"打开多个文件。来自Finder。如果Quicksilver以相同的方式处理多个文件,我不会感到惊讶,所以这个简单的方法可以为你工作。