How to check Mac OS X version at runtime

10,167

Solution 1

Update:

Use #define NSAppKitVersionNumber10_10_Max 1349

Old:

From 10.11 SDK

#define NSAppKitVersionNumber10_7_2 1138.23
#define NSAppKitVersionNumber10_7_3 1138.32
#define NSAppKitVersionNumber10_7_4 1138.47
#define NSAppKitVersionNumber10_8 1187
#define NSAppKitVersionNumber10_9 1265
#define NSAppKitVersionNumber10_10 1343
#define NSAppKitVersionNumber10_10_2 1344
#define NSAppKitVersionNumber10_10_3 1347

for 10.10.4 Its 1348.0(From NSLog output)

They increase decimal part for 10.10.x constant.

The workaround is to use CFBundleVersion value /System/Library/Frameworks/AppKit.framework/Resources/Info.plist on 10.11.

if (NSAppKitVersionNumber < 1391.12)
{
    /* On a 10.10.x or earlier system */
}

NOTE: My OS X 10.11 build version is 15A244a. If someone have first build , Please update the value in if condition.

Solution 2

Since Xcode 9.0, you can use code below. Reference to Apple documentation.

Swift

if #available(macOS 10.13, *) {
      // macOS 10.13 or later code path
} else {
      // code for earlier than 10.13
}

Objective-C

if (@available(macOS 10.13, *)) {
      // macOS 10.13 or later code path
} else {
      // code for earlier than 10.13
}

Solution 3

So the #define for 10_10 you see there is for 10.10.0.

If you look for older version numbers, you'll see specific #define's for MacOS 10.7.4, MacOS 10.5.3.

And what is happening here is that on a 10.10.4 machine (like yours and mine), the app kit number for 10.10.4 is greater than the one defined for 10.10.0.

That is, in swift, I did:

func applicationDidFinishLaunching(aNotification: NSNotification) {
    print("appkit version number is \(NSAppKitVersionNumber)")
}

And I got:

appkit version number is 1348.17

So your code is actually checking for 10.10.0 and older.

If you want to check for all versions of Yosemite & newer, you'll probably want to do something like

#ifdef NSAppKitVersionNumber10_11
if (floor(NSAppKitVersionNumber) < NSAppKitVersionNumber10_11)
{
    /* On a 10.10.x or earlier system */
}    
#endif

which will compile once you start building with Xcode 7 (and once Apple gets around to defining the official shipping version/build number for the El Capitan release)

FWIW, the Xcode 7 beta I have includes "NSAppKitVersionNumber10_10_3" in the 10.11 SDK.

Solution 4

If you need to support multiple systems (you can adapt method return value):

#import <objc/message.h>

+ (NSString *)systemVersion
{
  static NSString *systemVersion = nil;

  if (!systemVersion) {
    typedef struct {
      NSInteger majorVersion;
      NSInteger minorVersion;
      NSInteger patchVersion;
    } MyOperatingSystemVersion;

    if ([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) {
      MyOperatingSystemVersion version = ((MyOperatingSystemVersion(*)(id, SEL))objc_msgSend_stret)([NSProcessInfo processInfo], @selector(operatingSystemVersion));
      systemVersion = [NSString stringWithFormat:@"Mac OS X %ld.%ld.%ld", (long)version.majorVersion, version.minorVersion, version.patchVersion];
    }
    else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
      SInt32 versMaj, versMin, versBugFix;
      Gestalt(gestaltSystemVersionMajor, &versMaj);
      Gestalt(gestaltSystemVersionMinor, &versMin);
      Gestalt(gestaltSystemVersionBugFix, &versBugFix);
      systemVersion = [NSString stringWithFormat:@"Mac OS X %d.%d.%d", versMaj, versMin, versBugFix];
#pragma clang diagnostic pop
    }
  }

  return systemVersion;
}

Solution 5

Starting with Yosemite, you can use [NSProcessInfo processInfo].operatingSystemVersion and test the result in the struct NSOperatingSystemVersion.

Share:
10,167
Parag Bafna
Author by

Parag Bafna

My answers expressed here do not represent my employer's views Email : bafnaparag[AT]gmail[DOT]com

Updated on June 09, 2022

Comments

  • Parag Bafna
    Parag Bafna almost 2 years

    I am using below code to check OS X version at runtime.

    if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_10)
    {
        /* On a 10.10.x or earlier system */
    }
    

    But this condition return false on 10.10.4 OS X. I am using Xcode 6.3.2.

    enter image description here

    According to AppKit Release Notes for OS X v10.11, It should work.

    if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9) {
      /* On a 10.9.x or earlier system */
    } else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_10) {
      /* On a 10.10 - 10.10.x system */
    } else {
      /* 10.11 or later system */
    }
    
  • Parag Bafna
    Parag Bafna over 8 years
    Xcode 7 beta doesn't have NSAppKitVersionNumber10_11. I have added my workaround.
  • Parag Bafna
    Parag Bafna over 8 years
    Thank you but i am supporting 10.6 and above.
  • Marek H
    Marek H over 8 years
    do if respondsToSelector e.g. operatingSystemVersion If not use gestalt
  • coolcool1994
    coolcool1994 about 5 years
    Calling @available(macOS 10.14, ) causes "layout" method to be called infinitely to in NSTextView subclass. You need to do instead @available(,macOS 10.14)