Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Obtain Model Identifier string on OS X

Every Mac has a model identifier, for example "Macmini5,1". (These are shown in the System Information app.)

enter image description here

How can I programatically obtain this model identifier string?

like image 987
Nick Moore Avatar asked Nov 19 '13 11:11

Nick Moore


5 Answers

Swift 4+ using IOKit

import IOKit

func getModelIdentifier() -> String? {
    let service = IOServiceGetMatchingService(kIOMasterPortDefault,
                                              IOServiceMatching("IOPlatformExpertDevice"))
    var modelIdentifier: String?
    if let modelData = IORegistryEntryCreateCFProperty(service, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data {
        modelIdentifier = String(data: modelData, encoding: .utf8)?.trimmingCharacters(in: .controlCharacters)
    }

    IOObjectRelease(service)
    return modelIdentifier
}
like image 72
Ryan H Avatar answered Nov 12 '22 21:11

Ryan H


You can use sysctl

#import <Foundation/Foundation.h>
#import <sys/sysctl.h>

NSString *ModelIdentifier()
{
    NSString *result=@"Unknown Mac";
    size_t len=0;
    sysctlbyname("hw.model", NULL, &len, NULL, 0);
    if (len) {
        NSMutableData *data=[NSMutableData dataWithLength:len];
        sysctlbyname("hw.model", [data mutableBytes], &len, NULL, 0);
        result=[NSString stringWithUTF8String:[data bytes]];
    }
    return result;
}
like image 31
Parag Bafna Avatar answered Nov 12 '22 21:11

Parag Bafna


You can also use IOKit.framework. I think it's best choice.

This simple code example shows how to read model identifier from I/O Kit registry to NSString:

- (NSString *)modelIdentifier {
    io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, 
                                                       IOServiceMatching("IOPlatformExpertDevice"));

    CFStringRef model = IORegistryEntryCreateCFProperty(service, 
                                                        CFSTR("model"), 
                                                        kCFAllocatorDefault, 
                                                        0);

    NSString *modelIdentifier = [[NSString alloc] initWithData:(__bridge NSData *)model 
                                                      encoding:NSUTF8StringEncoding];

    CFRelease(model);
    IOObjectRelease(service);

    return modelIdentifier;
}

Strings "IOPlatformExpertDevice" and "model" in code above is used to read model identifier from I/O Kit registry. ioreg command line tool is your friend, when you want to find information from I/O Kit registry. This image shows those strings in ioreg output:

I hope this helps to use IOKit.framework.

like image 7
juniperi Avatar answered Nov 12 '22 22:11

juniperi


Answer from Ryan H is correct except improper conversion from null-terminated string to Swift String, giving result with \0 symbol in the end, which you may not expect, performing full match. This is corrected version:

static private func modelIdentifier() -> String? {
    let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
    defer { IOObjectRelease(service) }

    if let modelData = IORegistryEntryCreateCFProperty(service, "model" as CFString, kCFAllocatorDefault, 0).takeRetainedValue() as? Data {
        return modelData.withUnsafeBytes { (cString: UnsafePointer<UInt8>) -> String in
            return String(cString: cString)
        }
    }

    return nil
}
like image 6
Nikita Ivaniushchenko Avatar answered Nov 12 '22 23:11

Nikita Ivaniushchenko


You can get the same output from the system_profiler command. It has an -xml option that you can use. NSTask can run the command for you and you can parse the result.


Sample code:

#import <Foundation/Foundation.h>

NSString *ModelIdentifier() {
    NSPipe *pipe=[NSPipe pipe]; 
    NSTask *task=[[NSTask alloc] init];
    [task setLaunchPath:@"/usr/sbin/system_profiler"];
    [task setArguments:@[@"-xml", @"SPHardwareDataType"]];
    [task setStandardOutput:pipe];
    [task launch];

    NSData *outData=[[pipe fileHandleForReading] readDataToEndOfFile];
    NSString *outString=[[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];
    return [outString propertyList][0][@"_items"][0][@"machine_model"];
}
like image 2
Wain Avatar answered Nov 12 '22 23:11

Wain