Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to import <sys/utsname.h> in swift

I am creating a project in Swift. I want to display the modelName. I am following below link to get the modelName

http://myiosdevelopment.blogspot.co.uk/2012/11/getting-device-model-number-whether-its.html

The code in the link is written in objective-c. But I am not sure how to import this in Swift.

#import <sys/utsname.h>

Please someone help

like image 254
Funny Avatar asked Aug 19 '14 07:08

Funny


3 Answers

sys/utsname.h is imported into Swift by default, so you don't really need to import it from the bridging header. But using utsname from Swift is really painful though, as Swift imports fixed length C array as tuples. If you look into utsname.h, you see that the C struct members of utsname are all char array of 256 length:

#define _SYS_NAMELEN    256

struct  utsname {
    char    sysname[_SYS_NAMELEN];  /* [XSI] Name of OS */
    char    nodename[_SYS_NAMELEN]; /* [XSI] Name of this network node */
    char    release[_SYS_NAMELEN];  /* [XSI] Release level */
    char    version[_SYS_NAMELEN];  /* [XSI] Version level */
    char    machine[_SYS_NAMELEN];  /* [XSI] Hardware type */
};

Which gets imported into Swift like this:

var _SYS_NAMELEN: Int32 { get }

struct utsname {
    var sysname: (Int8, Int8, /* ... 254 more times "Int8, " here ... */) /* [XSI] Name of OS */
    var nodename: (Int8, Int8, /* ... snip ... */ ) /* [XSI] Name of this network node */
    var release: (Int8, Int8, /* ... snip ... */ ) /* [XSI] Release level */
    var version: (Int8, Int8, /* ... snip ... */ ) /* [XSI] Version level */
    var machine: (Int8, Int8, /* ... snip ... */ ) /* [XSI] Hardware type */
}

Yes, they're tuples with 256 Int8s. Which cases this hilarious autocompletion in Xcode:

Xcode completion of <code>utsname</code> initializer

Currently, there is no way to initialize an tuple in Swift without writing out all value, so initializing it as a local variable would be rather verbose, as you see above. There is also no way to convert the tuple to an array, so that huge tuple is also not very useful.

The easiest solution would be to implement it in Objective-C.

If you're dead set on using Swift, you can do this, but it's not pretty:

// Declare an array that can hold the bytes required to store `utsname`, initilized
// with zeros. We do this to get a chunk of memory that is freed upon return of
// the method
var sysInfo: [CChar] = Array(count: sizeof(utsname), repeatedValue: 0)

// We need to get to the underlying memory of the array:
let machine = sysInfo.withUnsafeMutableBufferPointer { (inout ptr: UnsafeMutableBufferPointer<CChar>) -> String in
    // Call uname and let it write into the memory Swift allocated for the array
    uname(UnsafeMutablePointer<utsname>(ptr.baseAddress))

    // Now here is the ugly part: `machine` is the 5th member of `utsname` and
    // each member member is `_SYS_NAMELEN` sized. We skip the the first 4 members
    // of the struct which will land us at the memory address of the `machine`
    // member
    let machinePtr = advance(ptr.baseAddress, Int(_SYS_NAMELEN * 4))

    // Create a Swift string from the C string
    return String.fromCString(machinePtr)!
}
like image 159
jou Avatar answered Nov 07 '22 06:11

jou


In Swift 4 you can just use the UIDevice model property:

func getPhoneModel() -> String { return UIDevice.current.model }

like image 20
Jeferson Alvarenga Avatar answered Nov 07 '22 06:11

Jeferson Alvarenga


my 2 cents for Swift 5 if You want to call utsname:

func platform() -> String {
    var systemInfo = utsname()
    uname(&systemInfo)
    let size = Int(_SYS_NAMELEN) // is 32, but posix AND its init is 256....
    
    let s = withUnsafeMutablePointer(to: &systemInfo.machine) {p in
        p.withMemoryRebound(to: CChar.self, capacity: size, {p2 in
            return String(cString: p2)
        })
        
    }
    return s
}
like image 2
ingconti Avatar answered Nov 07 '22 06:11

ingconti