I want to open one application instance only once, so I just do like
NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.my.app"];
in main.m
When I open the app from the console, the count of apps array will be 0. However, when I double click on the app, it will be 1
So can anyone tell me what's the difference between the double click and console open? or give me another way to check if there's already one instance running?

- 293
- 2
- 7
-
You might want to ask a separate question specifically about how to ensure only one process of your program is running. – Peter Hosey Dec 28 '12 at 07:13
2 Answers
that command queries the workspace and that is updated 'delayed'
when the app is started from finder, it is launched via the NSWorkspace
, so the workspace is updated right away
when the app is started via the console/xcode it is not started via NSWorkspace
, so that class returns 0 at the start. After the NSApplication
of your process is up, the workspace is informed and its 1.
=> it is always correct in - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
so either wait for NSApplication to start and THEN kill it (like you do now, but later)
OR
see Preventing multiple process instances on Linux for a way to do it without cocoa
OR
you look at launchd which can do this :) http://developer.apple.com/library/mac/#documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html
-
If there's was an instance running, I do not want the new `NSApplication` be run. What should I do? – Daniel Gao Dec 28 '12 at 02:36
-
1Wouldn't it be better to work through launchd instead of creating a pidfile somewhere? – Peter Hosey Dec 28 '12 at 07:12
-
The app could be opened by double click and called in my code. I want to make sure that there's only one instance running. And thank you for the answer about the difference. – Daniel Gao Dec 28 '12 at 09:18
-
either you wait with your check till appDidFinishLaunching and kill one there, OR you go with the pid way I posted – Daij-Djan Dec 28 '12 at 09:20
-
You can use below code. getBSDProcessList
function will return NSArray
of running process.[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;
}
Take a look at Technical Q&A QA1123 (Getting List of All Processes on Mac OS X)

- 1
- 1

- 22,812
- 8
- 71
- 144
-
You didn't answer the question. What's the difference between these two situations? Why does the code work in one but not the other? – Peter Hosey Dec 28 '12 at 07:11
-
@Parag Bafna thank you for your code Parag, but I do not wanna all of the processes, that's too heavy for my code – Daniel Gao Dec 28 '12 at 09:22
-
+ with the hint to use NSWorkspace you have just repeated non-working code – Daij-Djan Dec 28 '12 at 09:22
-
-
@Parag Bafna sorry, i cannot access stackoverflow these days, and i had done what i want to do, thanks for your sharing – Daniel Gao Jan 04 '13 at 02:38