【问题标题】:How to know what Mac OS the app is running on?如何知道应用程序在哪个 Mac OS 上运行?
【发布时间】:2012-06-18 18:54:12
【问题描述】:

我在一些项目中看到过类似的东西:

#if .....
    code...
#endif

但我现在找不到...
假设,例如,如果应用程序在 10.8 上运行,则应用程序执行 1 件事,否则应用程序执行其他操作。 用什么代码检查它是否在 10.8 上运行?
谢谢。

【问题讨论】:

  • 我做了一个快速检查,这个答案可能对你有帮助:stackoverflow.com/questions/157759/…
  • CPP #define/#if 在这里不是你的朋友。那是一个编译开关(例如,什么平台/功能被定位)。
  • #if .... #endif 是一个在编译时运行的预处理器,我用它来确定 dev、qa(test) 和 release。
  • @PedroVieira 是的,但该问题的答案是最新的和正确的。 Stack Overflow 是一个公共 wiki,优先选择最佳和最正确的答案,不一定是第一个。

标签: objective-c xcode macos cocoa osx-mountain-lion


【解决方案1】:

您可以像这样获取操作系统版本:

NSString *version = [[NSProcessInfo processInfo] operatingSystemVersionString];

NSLog(version);

输出:


我看到你想得到一个版本。可以这样做:
NSString *version = [[NSProcessInfo processInfo] operatingSystemVersionString];

NSRange range = NSMakeRange(8, 4);
NSString *justVersion = [version substringWithRange: range];

NSLog(@"%@", justVersion);

结果:

为了检查:

if ([justVersion isEqualToString:@"10.7"]) {
    code...
}
else {
    ...
}

【讨论】:

  • 在文档中:“这个字符串不适合解析。”
  • 另请注意,该字符串的格式因用户的语言环境而异。
  • 同意,非常非常错误。事实上,doco 表明使用 [[NSProcessInfo processInfo] operatingSystemVersionString];仅用于显示目的,不应解析。
【解决方案2】:

您可以从uname -r 命令获取当前版本(实际上是内核版本,尽管它很容易映射到 Mac OS X 版本),从提供版本名称、版本和构建的sw_vers 命令获取标识符,或者来自 Gestalt() 函数(无论如何,在当前版本的 Mac OS X 上)。最安全的方法可能是读取sw_vers 的输出,该输出格式稳定且易于解析。

但请注意,您可能不想知道您使用的操作系统版本。您可能想要做的是测试特定功能是否可用。您可以通过弱链接框架、弱类引用或检查类是否响应适合您感兴趣的功能的选择器来做到这一点。

【讨论】:

    【解决方案3】:

    您可能问错了问题。除非在极少数情况下,您不应该关心用户正在运行的系统版本。相反,您应该检查您感兴趣的特定内容是否可用。

    例如,如果 Apple 在 Mac OS X 10.9 中引入了您想要使用的 MagicHologram 类,则您无需检查用户是否正在运行 Mac OS X 10.9。相反,您检查 MagicHologram 类是否可用。如果是,您可以使用它。如果没有,则不可用。甚至不知道为什么。也许他们正在运行 10.8。但也许是五年后,Apple 决定完全放弃 MagicHologram 课程。

    (另外,请记住,您需要弱链接到提供 MagicHologram 类的库 HologramKit。)

    同样,如果他们向 NSString 引入新方法,而不是检查操作系统版本,您会检查 NSString 是否知道新方法。

    也就是说,NSApplication.h 包含一个名为NSAppKitVersionNumber 的外部常量。您可以将其与NSAppKitVersionNumber10_7 之类的常量进行比较,后者(应该注意)是 1138 之类的数字,而不是 10.7。只有少数地方是合适的,主要是类是私有的和未记录的,但在记录并成为 SDK 的公共部分的一部分之前进行了重大更改。此外,如果您想避免已修复的特定错误,这可能会有所帮助。

    回顾一下:

    1. 检测单个类和方法,应涵盖 99.44% 的案例。
    2. 使用NSAppKitVersionNumber 和NSAppKitVersionNumber10_7 来涵盖类或方法检测会欺骗您的情况。
    3. 前两点涵盖所有正常情况。你不应该再往前走了。但是,如果您必须有基于人性化版本的行为,请查看下面的 abarnert 的答案。这是获取它们的最明智的方法。
    4. 不要使用operatingSystemVersionString,它被明确列为不安全解析。

    参考/更多信息:

    • SDK Compatibility Guide “如果您希望您的应用程序针对特定版本或多个版本的 iOS 或 Mac OS X,请阅读此文档。”

    【讨论】:

      【解决方案4】:

      一个快速的方法是:

      if ( NSAppKitVersionNumber >= NSAppKitVersionNumber10_7 ) {
      
          // Do stuff for Lion or later
      }
      

      更多here.

      您可以在 NSApplication.h 中看到所有可用的常量,您可以通过在 Xcode 中使用 Open Quickly... (Cmd-Shift O) 来获得这些常量。

      头文件提供了一些非常有趣的阅读材料,如果您愿意的话。

      【讨论】:

      • 我觉得快捷键默认是Cmd-Shift-D
      • 这个问题是它没有涵盖 Mac OS X 的每个版本,并且如果(例如,如果您试图报告操作系统版本以进行诊断目的。)
      【解决方案5】:

      正如其他人在上面所说的(我会选择 Steven Fisher 的答案),您通常实际上并不希望获得版本号。

      如果您只需要与主要的 OS X 版本进行比较,直到您正在使用的当前 SDK 的版本,NSAppKitVersionNumber(如 Monolo 的回答)是正确的方法。

      如果您出于某种原因确实需要获取版本号(例如,为了记录有关您的用户的分析,以便您决定何时停止支持 10.6.0-10.6.5),请按以下步骤操作:

      #import <CoreServices/CoreServices.h>
      SInt32 majorVersion, minorVersion, bugFixVersion;
      Gestalt(gestaltSystemVersionMajor, &majorVersion);
      Gestalt(gestaltSystemVersionMinor, &minorVersion);
      Gestalt(gestaltSystemVersionBugFix, &bugFixVersion);  
      

      对于 10.7.3,这给出了 majorVersion = 10、minorVersion = 7、bugFixVersion = 3。

      10.7 文档删除了直接建议 Gestalt 作为获取 OS 版本的方式的段落,但它仍然没有被弃用或遗留,也没有其他建议。事实上,获取此信息的所有其他方式(解析 -[NSProcessInfo operatingSystemVersionString]、在“kern.osrelease”上调用 sysctlbyname 并将 Darwin 内核版本转换为 OS X 版本等)在某处都明确地被反指示。所以,如果你真的想这样做,这就是这样做的方法。

      请记住,正如 1989 年 System 6.0.4 的发行说明所述,这个新 API 可能不是永久性的,可能会在未来版本的操作系统中被删除。

      【讨论】:

      • 确保您在执行此操作时正确编写了比较。我公司的某个人(不是我(眨眼))曾经编写了一个例程,检测到 10.4.0 比 10.3.1 旧,因为 0 低于 1。:)
      • @StevenFisher:我从来没有这样做过;当我的意思是更大时,我只是做了更大的平等。 :) 但更常见的问题是将整个内容转换为字符串,然后比较字符串,这在 10.4.10 出现之前完美运行(因为“10.4.10”小于“10.4.9”)。您可以使用 NSNumericSearch/kCFCompareNumerically 来避免这种情况——但更简单的是,只需在字符串化之前比较数字即可。
      【解决方案6】:

      这是我如何做的代码。我喜欢这种方式,主要是因为我不必 A) 依赖 NSTask 或 B) 依赖许多进程可以访问的任何文件 I/O。

      static NSString* const kVarSysInfoVersionFormat  = @"%@.%@.%@ (%@)";
      static NSString* const kVarSysInfoKeyOSVersion = @"kern.osrelease";
      static NSString* const kVarSysInfoKeyOSBuild   = @"kern.osversion";
      
      - (NSString *) _strControlEntry:(NSString *)ctlKey {
      
          size_t size = 0;
          if ( sysctlbyname([ctlKey UTF8String], NULL, &size, NULL, 0) == -1 ) return nil;
      
          char *machine = calloc( 1, size );
      
          sysctlbyname([ctlKey UTF8String], machine, &size, NULL, 0);
          NSString *ctlValue = [NSString stringWithCString:machine encoding:[NSString defaultCStringEncoding]];
      
          free(machine); return ctlValue;
      }
      
      - (NSString *) getOSVersionInfo {
      
          NSString *darwinVer = [self _strControlEntry:kVarSysInfoKeyOSVersion];
          NSString *buildNo = [self _strControlEntry:kVarSysInfoKeyOSBuild];
          if ( !darwinVer || !buildNo ) return nil;
      
          NSString *majorVer = @"10", *minorVer = @"x", *bugFix = @"x";
          NSArray *darwinChunks = [darwinVer componentsSeparatedByCharactersInSet:[NSCharacterSet punctuationCharacterSet]];
      
          if ( [darwinChunks count] > 0 ) {
      
              NSInteger firstChunk = [(NSString *)[darwinChunks objectAtIndex:0] integerValue];
              minorVer = [NSString stringWithFormat:@"%ld", (firstChunk - 4)];
              bugFix = [darwinChunks objectAtIndex:1];
      
          } return [NSString stringWithFormat:kVarSysInfoVersionFormat, majorVer, minorVer, bugFix, buildNo];
      }
      

      享受吧!

      【讨论】:

        【解决方案7】:

        正如 Steven Fisher 所说,您不应该检查系统版本,而是检查要使用的类或方法的可用性。

        检查特定类是否可用

        if ([NSHologram class]) {
           // Create an instance of the class and use it.
        } else {
           // The Hologram class is not available.
        }
        

        要检查特定方法是否可用,请使用

        NSString* hologramText = @"Hologram";
        if ([hologramText respondsToSelector:@selector(convertHologram)]) {
            [hologramText convertHologram];
        }
        

        然而对于方法检查,该方法必须在您构建应用程序的系统上可用,否则您将收到编译错误。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-04-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-06-23
          • 2014-03-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多