通常一个应用程序包的OS X只能开始一次,不过通过简单的复制的束相同的应用程序可以启动了两次。什么是最佳的战略的检测和制止这种可能性?

在窗户的这种效果可以简单地通过应用创造一个名为资源在启动和随后退出如果指定的资源不能创建的,表明这另一个运行过程,已经创建了同样的资源。这些资源都放在一个可靠的方法上的Windows的应用程序时退出。

这个问题,我已经看到当研究这个是Api OS X保持国家在文件系统和因此使得该战略使用的windows不可靠,我...e挥之不去后的文件不正确的退出可能错误地表明,应用程序已运行。

Api我可以用来实现同样的效果OS X是:posix、碳和提升。

想法?

有帮助吗?

解决方案

一个低级别的解决方案是使用群()。

每个实例都将试图锁定在启动一个文件,如果锁定失败,则另一个实例已在运行。鸡群会被自动释放时,你的程序退出,所以没有对陈旧的锁后顾之忧。

请注意,无论您选择的解决方案,你需要做什么就意味着拥有“多个实例”一个明智的决定。具体地,如果多个用户在同一时间运行应用程式,是可以吗?

其他提示

这是非常容易在雪豹:

- (void)deduplicateRunningInstances {
    if ([[NSRunningApplication runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]] count] > 1) {
        [[NSAlert alertWithMessageText:[NSString stringWithFormat:@"Another copy of %@ is already running.", [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey]] 
                         defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"This copy will now quit."] runModal];

        [NSApp terminate:nil];
    }
}

请参阅 HTTP://博客.jseibert.com /后/ 1167439217 /去重复运行-实例 - 或如何对检测-如果获得更多的信息。

有被称为神秘的Info.plist键“申请禁止多个实例”,但它似乎并没有为我工作。我写一个CLI应用程序,并从包内执行它。也许它会在一个GUI应用程序的工作,但我还没有尝试过。

前面已经提到的Cocoa应用程序通常不会让你在同一时间运行多个实例。

在一般情况下,可可的方式来解决这个看在NSWorkspace launchedApplications。这返回一个包含字典的每个应用推出一个NSArray。你可以遍历数组,看看你正在寻找应用程序已经在运行。我会建议您使用的关键NSApplicationBundleIdentifier值具有像“com.mycompany.myapp”而不是找名称的值。如果你需要找到一个应用程序捆绑标识,你可以看一下在应用程序包的Info.plist文件。

首先,它是"Mac OS X"或"OS X"。没有这样的东西"OS/X"。

第二,Mac OS X不来与提高;你会需要捆绑它与应用程序。

第三,大多数的碳是不是可以在64位。这是一个明确的信号,那些部分的碳将去总有一天(当的苹果放弃32位在其硬件)。或早或晚,你将需要重写你的应用与可可或放弃。

通常一个应用程序包的操作系统/X只能开始一次,不过通过简单的重新命名束相同的应用程序可以启动了两次。

没有它不能。启动重新命名或移动应用程序只会激活(带来前)的进程已经运行;它不会开始一个新的,第二个进程同第一个。


有几种方法来告诉应用程序是否已经运行。在每一种情况下,你这样做,在启动:

  1. 使用可可的NSConnection注册的连接有一个恒定的名称。这将失败,如果名字已经注册。(你可以使用基金会,从一个碳应用程序;这是应用工具包,你要小心的。)
  2. 使用过程管理扫描过程中的列表进程的束的标识符相匹配的一个你要找的。捆绑标识符,并不是不可改变的,但是很难改变过名或位置。
  3. 如果你想的时候看到有人行第二次复制自己,可以使用CFNotificationCenter:

    1. 添加自己作为一个观察员"。yourdomain.yourappname.LaunchResponse".
    2. 后一种通知在名为"com.yourdomain.yourappname.LaunchCall".
    3. 添加自己作为一个观察员"。yourdomain.yourappname.LaunchCall".

    在你的观察回的电话通知后的反应的通知。
    在你的观察回调响应的通知,退出。

    因此,当第一个进程的开始,它将呼吁并没有得到任何响应;当第二个进程的开始,它将调用,得到的回应的第一个进程,并在考虑到第一个。

这是对夫特2.0的罗马和杰夫的答案的组合:如果具有相同包ID的应用程序的另一实例已在运行,显示一个警报,激活其它实例,并退出该重复实例

func applicationDidFinishLaunching(aNotification: NSNotification) {
    /* Check if another instance of this app is running. */
    let bundleID = NSBundle.mainBundle().bundleIdentifier!
    if NSRunningApplication.runningApplicationsWithBundleIdentifier(bundleID).count > 1 {
        /* Show alert. */
        let alert = NSAlert()
        alert.addButtonWithTitle("OK")
        let appName = NSBundle.mainBundle().objectForInfoDictionaryKey(kCFBundleNameKey as String) as! String
        alert.messageText = "Another copy of \(appName) is already running."
        alert.informativeText = "This copy will now quit."
        alert.alertStyle = NSAlertStyle.CriticalAlertStyle
        alert.runModal()

        /* Activate the other instance and terminate this instance. */
        let apps = NSRunningApplication.runningApplicationsWithBundleIdentifier(bundleID)
        for app in apps {
            if app != NSRunningApplication.currentApplication() {
                app.activateWithOptions([.ActivateAllWindows, .ActivateIgnoringOtherApps])
                break
            }
        }
        NSApp.terminate(nil)
    }

    /* ... */
}

了解 IPC 什么?你可以打开一个套接字,并与其他启动的实例进行谈判。你必须要小心,虽然,它的工作原理如果两个应用程序在同一时间开始。

我不能为您提供示例代码,我没有(还没有,但我会很快)中使用它。

这是一个版本SEB的的的夫特3.0 :如果具有相同包ID已经在运行的应用程序的另一实例中,示出了警报,激活其它实例,并退出该重复实例

func applicationDidFinishLaunching(aNotification: NSNotification) {
    /* Check if another instance of this app is running. */
    let bundleID = Bundle.main.bundleIdentifier!
    if NSRunningApplication.runningApplications(withBundleIdentifier: bundleID).count > 1 {
         /* Show alert. */
         let alert = NSAlert()
         alert.addButton(withTitle: "OK")
         let appName = Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) as! String
         alert.messageText = "Another copy of \(appName) is already running."
         alert.informativeText = "This copy will now quit."
         alert.alertStyle = NSAlert.Style.critical
         alert.runModal()

         /* Activate the other instance and terminate this instance. */
         let apps = NSRunningApplication.runningApplications(withBundleIdentifier: bundleID)
             for app in apps {
                  if app != NSRunningApplication.current {
                      app.activate(options: [.activateAllWindows, .activateIgnoringOtherApps])
                      break
                  }
             }
                NSApp.terminate(nil)
         }   
       /* ... */
}

检测是否应用与相同bundleID运行时,激活它,并关闭什么开始。

- (id)init method of < NSApplicationDelegate >

    NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]];
    if ([apps count] > 1)
    {
        NSRunningApplication *curApp = [NSRunningApplication currentApplication];
        for (NSRunningApplication *app in apps)
        {
            if(app != curApp)
            {
                [app activateWithOptions:NSApplicationActivateAllWindows|NSApplicationActivateIgnoringOtherApps];
                break;
            }
        }
        [NSApp terminate:nil];
        return nil;
    }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top