如何知道应用程序运行在哪个Mac OS上?

8

我在一些项目中看到过类似于以下代码:

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

但是我现在找不到了...
例如,假设应用程序正在运行于10.8系统上,则应用程序执行一项操作,否则执行另一项操作。 用什么代码来检查它是否在10.8版本上运行?
谢谢。


我进行了快速检查,这个答案可能会对你有所帮助:https://dev59.com/bXVC5IYBdhLWcg3w4VRz - CBredlow
5
在这里,一个 CPP 的 #define/#if 并不是你的朋友。那是一个编译开关(例如,目标平台/功能)。 - user166390
#if .... #endif 是一个在编译时运行的预处理器,我使用它来区分开发、测试和发布环境。 - Popeye
@JakePetroules 如果你仔细看,我的问题是在那个问题之前问的,所以那个问题是重复的。 - Pedro Vieira
1
@PedroVieira 是的,但那个问题有最新和正确的答案。Stack Overflow是一个公共维基,偏好于最好和最正确的答案,而不一定是最先的答案。 - Jake Petroules
7个回答

24
你可能在问错问题。除非非常罕见的情况,你不需要关心用户运行的系统版本。相反,你应该检查你感兴趣的特定内容是否可用。
例如,如果苹果公司在Mac OS X 10.9中引入了一个MagicHologram类,你想要使用它,你不需要检查用户是否运行Mac OS X 10.9,而是检查MagicHologram类是否可用。如果可用,你就可以使用它。如果不可用,无论原因是什么都无关紧要。也许他们正在运行10.8,但也可能是五年后,苹果已经决定完全放弃MagicHologram类。
(此外,请记住,你需要对提供MagicHologram类的库HologramKit进行弱链接。)
同样地,如果他们向NSString添加了一个新方法,而不是检查操作系统版本,你应该检查NSString是否知道这个新方法。
说到这里,NSApplication.h包含一个名为“NSAppKitVersionNumber”的外部常量。你可以将其与类似于“NSAppKitVersionNumber10_7”的常量进行比较,这些常量(应该注意)是像1138这样的数字,而不是10.7。只有在几个情况下才适用,主要是在类是私有且未记录文档但在成为SDK公共部分之前发生了重大变化的情况下。此外,如果你想避免已修复的特定错误,这可能会有所帮助。
总结一下:
1.检测单独的类和方法,这应该涵盖99.44%的情况。
2.使用NSAppKitVersionNumber和NSAppKitVersionNumber10_7来覆盖那些类或方法检测会误导你的情况。
3.前两点涵盖了所有正常的情况。不过,如果你必须根据人性化版本进行某些操作,请查看下面的abarnert的答案。这是最明智的获取它们的方法。
  • 不要使用 operatingSystemVersionString,该属性被明确列为不安全的解析。
  • 参考/更多信息:

    • SDK 兼容性指南 "如果您想让应用程序针对特定版本或多个版本的 iOS 或 Mac OS X 进行定位,请阅读此文档。"
      • 使用基于 SDK 的开发 描述了如何使用弱链接的类、方法和函数来支持在多个操作系统版本上运行。

    12

    一个快速的方法是:

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

    更多信息 在此

    您可以通过在Xcode中使用“快速打开”(Cmd-Shift O)访问NSApplication.h中提供的所有常量。

    如果您有兴趣,头文件为一些令人惊讶的有趣阅读材料提供了支持。


    我认为默认的快捷键是Cmd-Shift-D。 - cdelacroix
    2
    问题在于它并不涵盖每个版本的Mac OS X,并且没有办法未雨绸缪(例如,如果您正在尝试报告操作系统版本以进行诊断目的)。 - Jonathan Grynspan

    4

    正如其他人所说(我选择Steven Fisher的答案),您通常实际上不需要获取版本号。

    如果您只需要对当前使用的SDK版本进行与主要OS X版本的比较,则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版本,这将会得到主要版本号=10,次要版本号=7,错误修复版本号=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。 :) - Steven Fisher
    @StevenFisher:我从来没有这样做过;我本来想用大于号,结果写成了大于等于号。:) 但更常见的问题是将整个内容转换为字符串,然后比较字符串,这在10.4.10推出之前完美运行(因为“10.4.10”小于“10.4.9”)。您可以使用NSNumericSearch/kCFCompareNumerically来避免这种情况——甚至更简单的方法是在将其转换为字符串之前比较数字。 - abarnert

    2
    您可以通过uname -r命令(实际上是内核版本,但很容易映射到Mac OS X版本),通过sw_vers命令获取发布名称、版本和构建标识符,或者在当前版本的Mac OS X上使用Gestalt()函数来获取当前版本。最安全的方法可能是读取sw_vers的输出,这是一种稳定的格式,易于解析。
    请注意,您可能不想知道您所在的操作系统版本。您可能想要做的是测试特定功能是否可用。您可以通过弱链接框架、弱类引用或检查类是否响应与您感兴趣的特定功能相应的选择器来实现此目的。

    2
    如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];
    }
    

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


    0
    这是我实现它的代码。我喜欢这种方式,主要是因为我不必 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];
    }
    

    享受吧!


    -4

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

    NSString *version = [[NSProcessInfo processInfo] operatingSystemVersionString];
    
    NSLog(version);
    

    输出:

    截图


    我看到您只想获取版本号。可以像这样完成:

    NSString *version = [[NSProcessInfo processInfo] operatingSystemVersionString];
    
    NSRange range = NSMakeRange(8, 4);
    NSString *justVersion = [version substringWithRange: range];
    
    NSLog(@"%@", justVersion);
    

    结果:

    screenshot

    而且用于检查:

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

    10
    文档中写道:“这个字符串不适合解析。” - user23743
    1
    还要注意,该字符串的格式因用户所在地区而异。 - Jonathan Grynspan
    1
    同意,非常非常错误。实际上,文档表明使用[[NSProcessInfo processInfo] operatingSystemVersionString];仅用于显示目的,不应解析。 - Arvin

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接