Search code examples
xcodemacosoperating-systemosx-yosemiteosx-yosemite-beta

How to get the OS Version String in MAC 10.10 without using gestalt


My objective is to collect the OS Version, release details of MAC 10.10.

I have found a way to collect the version details in MAC 10.10 and as well as from prev. version from the link

How do I determine the OS version at runtime in OS X or iOS (without using Gestalt)?

While I compile it is throwing error at "objc_msgSend_stret", when i search the /usr/include/objc folder itself was not exist in my MAC. i could see only gcc present and all my code was build with it.

Is there any best way to copy the output of

[[NSProcessInfo processInfo], @selector(operatingSystemVersion)] to a struct as "MyOperatingSystemVersion"?

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));
    // do whatever you want with the version struct here
}
else {
    UInt32 systemVersion = 0;
    OSStatus err = Gestalt(gestaltSystemVersion, (SInt32 *) &systemVersion);
    // do whatever you want with the systemVersion as before
}

Solution

  • I'm guessing that you aren't building this with the 10.10 SDK, otherwise you could simply remove your call to objc_msgSend_stret and call operatingSystemVersion directly.

    // Built with 10.10 SDK
    if ([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) {
        NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
        // do whatever you want with the version struct here
    }
    else {
        UInt32 systemVersion = 0;
        OSStatus err = Gestalt(gestaltSystemVersion, (SInt32 *) &systemVersion);
        // do whatever you want with the systemVersion as before
    }
    

    If you're using an earlier SDK, then NSOperatingSystemVersion and -[NSProcessInfo operatingSystemVersion] are both undefined. Since you can't use -[NSProcessInfo operatingSystemVersion] without getting a compiler error, the safer way to call it and get the return value of a non-object type is with NSInvocation. This is still technically risky because you're assigning the return value to a different type of struct (MyOperatingSystemVersion vs. NSOperatingSystemVersion), but you have defined them both the same so it should be ok. I tested this with Xcode 5 / 10.9 SDK and it worked fine.

    // Built with 10.9 or earlier SDKs
    if ([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) {
        MyOperatingSystemVersion version;
        NSMethodSignature *methodSignature = [[NSProcessInfo processInfo] methodSignatureForSelector:@selector(operatingSystemVersion)];
        NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature];
        inv.selector = @selector(operatingSystemVersion);
        [inv invokeWithTarget:[NSProcessInfo processInfo]];
        [inv getReturnValue:&version];
        // do whatever you want with the version struct here
    }
    else {
        UInt32 systemVersion = 0;
        OSStatus err = Gestalt(gestaltSystemVersion, (SInt32 *) &systemVersion);
        // do whatever you want with the systemVersion as before
    }
    

    That should take care of the problem, but the safest thing to do is build with the 10.10 SDK and use the first example.