bdesham
bdesham

Reputation: 16089

Using sysctlbyname() from Swift

I’m using the code from this Gist to determine which iOS device (e.g. iPhone5,1) my app is running on:

- (NSString *)platform
{
    size_t size;
    sysctlbyname("hw.machine", NULL, &size, NULL, 0);
    char *machine = malloc(size);
    sysctlbyname("hw.machine", machine, &size, NULL, 0);
    NSString *platform = [NSString stringWithUTF8String:machine];
    free(machine);
    return platform;
}

The Swift documentation indicates that C data types are well-supported, but it doesn’t say anything about C functions. Is there a pure Swift way to retrieve the machine identifier, or will I have to bridge into Objective-C for this?

Upvotes: 27

Views: 10012

Answers (2)

Martin R
Martin R

Reputation: 539965

You can do the same in Swift (error checking omitted for brevity):

func platform() -> String {
    var size : Int = 0 // as Ben Stahl noticed in his answer
    sysctlbyname("hw.machine", nil, &size, nil, 0)
    var machine = [CChar](count: size, repeatedValue: 0)
    sysctlbyname("hw.machine", &machine, &size, nil, 0)
    return String.fromCString(machine)!
}

Update for Swift 3:

func platform() -> String {
    var size = 0
    sysctlbyname("hw.machine", nil, &size, nil, 0)
    var machine = [CChar](repeating: 0,  count: size)
    sysctlbyname("hw.machine", &machine, &size, nil, 0)
    return String(cString: machine)
}

Update for Swift 6:

String(cString:) is now deprecated, attribution goes to https://stackoverflow.com/a/79423711/1187415 .

func platform() -> String? {
    var size = 0
    if sysctlbyname("hw.machine", nil, &size, nil, 0) != 0 {
        return nil
    }
    var machine = [CChar](repeating: 0,  count: size)
    if sysctlbyname("hw.machine", &machine, &size, nil, 0) != 0 {
        return nil
    }
    return String(utf8String: machine)
}

Upvotes: 59

Ben Stahl
Ben Stahl

Reputation: 1159

As of Swift 1.2 (Xcode 6.3 beta-2), @MartinR's code above needs to be modified slightly. sysctlbyname needs a CChar array (i.e. C string) for the first parameter, and an Int (instead of Uint) for the "size" parameter.

func platformModelString() -> String? {
    if let key = "hw.machine".cString(using: String.Encoding.utf8) {
        var size: Int = 0
        sysctlbyname(key, nil, &size, nil, 0)
        var machine = [CChar](repeating: 0, count: Int(size))
        sysctlbyname(key, &machine, &size, nil, 0)
        return String(cString: machine)
    }
    return nil
}

EDIT: Updated 2017-01-04 for Swift 3 syntax

Upvotes: 16

Related Questions