【问题标题】:what's the difference between the double click and console open双击和控制台打开有什么区别
【发布时间】:2012-12-28 01:27:33
【问题描述】:

我只想打开一个应用程序实例一次,所以我只是像
NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.my.app"]; in main.m
当我从控制台打开应用程序时,应用程序数组的计数将为 0。但是,当我双击应用程序时,它将为 1
那么谁能告诉我双击和控制台打开有什么区别?或者给我另一种方法来检查是否已经有一个实例在运行?

【问题讨论】:

  • 你可能想问一个单独的问题,专门关于如何确保你的程序只有一个进程在运行。

标签: macos cocoa


【解决方案1】:

该命令查询工作区并“延迟”更新

当应用程序从 finder 启动时,它会通过NSWorkspace 启动,因此工作区会立即更新

当应用程序通过控制台/xcode 启动时,它不是通过 NSWorkspace 启动的,因此该类在开始时返回 0。在您的进程的NSApplication 启动后,将通知工作区及其 1。

=> 在- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 中总是正确的


所以要么等待 NSApplication 启动然后杀死它(就像你现在做的那样,但稍后)

请参阅 Preventing multiple process instances on Linux 了解不使用可可的方法

你看看可以做到这一点的launchd :) http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html

【讨论】:

  • 如果有一个实例正在运行,我不想运行新的NSApplication。我该怎么办?
  • 通过launchd而不是在某个地方创建一个pidfile不是更好吗?
  • 应用程序可以通过双击打开并在我的代码中调用。我想确保只有一个实例在运行。感谢您对差异的回答。
  • 要么等待检查直到 appDidFinishLaunching 并在那里杀死一个,要么使用我发布的 pid 方式
  • 或者你看看可以做到这一点的launchd :)
【解决方案2】:

您可以使用以下代码。 getBSDProcessList 函数将返回正在运行的进程的NSArray[1]

static int GetBSDProcessList(kinfo_proc **procList, size_t *procCount)
// Returns a list of all BSD processes on the system.  This routine
// allocates the list and puts it in *procList and a count of the
// number of entries in *procCount.  You are responsible for freeing
// this list (use "free" from System framework).
// On success, the function returns 0.
// On error, the function returns a BSD errno value.
{
    int                 err;
    kinfo_proc *        result;
    bool                done;
    static const int    name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
    // Declaring name as const requires us to cast it when passing it to
    // sysctl because the prototype doesn't include the const modifier.
    size_t              length;

    //    assert( procList != NULL);
    //    assert(*procList == NULL);
    //    assert(procCount != NULL);

    *procCount = 0;

    // We start by calling sysctl with result == NULL and length == 0.
    // That will succeed, and set length to the appropriate length.
    // We then allocate a buffer of that size and call sysctl again
    // with that buffer.  If that succeeds, we're done.  If that fails
    // with ENOMEM, we have to throw away our buffer and loop.  Note
    // that the loop causes use to call sysctl with NULL again; this
    // is necessary because the ENOMEM failure case sets length to
    // the amount of data returned, not the amount of data that
    // could have been returned.

    result = NULL;
    done = false;
    do {
        assert(result == NULL);

        // Call sysctl with a NULL buffer.

        length = 0;
        err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
                     NULL, &length,
                     NULL, 0);
        if (err == -1) {
            err = errno;
        }

        // Allocate an appropriately sized buffer based on the results
        // from the previous call.

        if (err == 0) {
            result = malloc(length);
            if (result == NULL) {
                err = ENOMEM;
            }
        }

        // Call sysctl again with the new buffer.  If we get an ENOMEM
        // error, toss away our buffer and start again.

        if (err == 0) {
            err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1,
                         result, &length,
                         NULL, 0);
            if (err == -1) {
                err = errno;
            }
            if (err == 0) {
                done = true;
            } else if (err == ENOMEM) {
                assert(result != NULL);
                free(result);
                result = NULL;
                err = 0;
            }
        }
    } while (err == 0 && ! done);

    // Clean up and establish post conditions.

    if (err != 0 && result != NULL) {
        free(result);
        result = NULL;
    }
    *procList = result;
    if (err == 0) {
        *procCount = length / sizeof(kinfo_proc);
    }

    assert( (err == 0) == (*procList != NULL) );

    return err;
}

+ (NSArray*)getBSDProcessList
{
    NSMutableArray *ret = [NSMutableArray arrayWithCapacity:1];
    kinfo_proc *mylist;
    size_t mycount = 0;
    mylist = (kinfo_proc *)malloc(sizeof(kinfo_proc));
    GetBSDProcessList(&mylist, &mycount);
    int k;
    for(k = 0; k < mycount; k++) {
        kinfo_proc *proc = NULL;
        proc = &mylist[k];
        NSString *fullName = [[self infoForPID:proc->kp_proc.p_pid] objectForKey:(id)kCFBundleNameKey];
        NSLog(@"fullName %@", fullName);
        if (fullName != nil) 
        {
            [ret addObject:fullName];
        }                                        
    }
    free(mylist);  
    return ret;
}

+ (NSDictionary *)infoForPID:(pid_t)pid 
{
    NSDictionary *ret = nil;
    ProcessSerialNumber psn = { kNoProcess, kNoProcess };
    if (GetProcessForPID(pid, &psn) == noErr) {
        CFDictionaryRef cfDict = ProcessInformationCopyDictionary(&psn,kProcessDictionaryIncludeAllInformationMask); 
        ret = [NSDictionary dictionaryWithDictionary:(NSDictionary *)cfDict];
        CFRelease(cfDict);
    }
    return ret;
}

看看Technical Q&A QA1123 (Getting List of All Processes on Mac OS X)

【讨论】:

  • 您没有回答问题。这两种情况有什么区别?为什么代码在其中一个起作用,而另一个不起作用?
  • @Parag Bafna 谢谢你的代码 Parag,但我不想要所有的进程,这对我的代码来说太重了
  • + 提示您使用 NSWorkspace 您刚刚重复了非工作代码
  • @Daniel Gao 你说的“太重”是什么意思?
  • @Parag Bafna 抱歉,这些天我无法访问 stackoverflow,我已经完成了我想做的事情,感谢您的分享
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-24
  • 1970-01-01
相关资源
最近更新 更多