Using sysctlbyname() from Swift
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)
}
Use the sysctlbyname function within a Linux Swift Package
So one can add C, C++ or Objective-C targets to a Swift package so it's possible to import the needed system headers, and then create some wrapper functions, that makes what is needed, accessible to Swift, but this breaks Swift playgrounds app development compatibility, since that support Swift-only targets (a possible workaround is to put the C/C++ target in a separate swift package to use it as a dependecy conditionally just for linux, for more details see the relative swift package documentation).
So adding a C/C++ target could have solved the problem, BUT the issue is that in the Linux kernel version 5.5 and onwards the sysctl
functions have been deprecated and even on the older kernels they weren't available on all the cpu architectures Linux supports, and so on a computer running a recent kernel or some particular non-x86 cpu architecture, such Swift package would not have been built successfully.
The current way to access the information that used to be provided by the sysctl
functions is to read it directly from the file system inside the /proc/sys
directory and it works on all supported cpu architectures, and it's were the sysctl
command line utility gets that data.
So only on linux the code have to modified like this, to successfully gather that data on all platforms:
import Foundation
#if os(Linux)
import Glibc //? not sure about where i can find `sysctlbyname` in linux without using C headers
#else
import Darwin.sys.sysctl
#endif
///Generic protocol to allow easy fetching of values out of `sysctlbyname`
public protocol SysctlFetch{
static var namePrefix: String {get}
}
public extension SysctlFetch{
#if !os(Linux)
///Gets a `String` from the `sysctlbyname` function
static func getString(_ valueName: String) -> String?{
var size: size_t = 0
let name = namePrefix + valueName
var res = sysctlbyname(name, nil, &size, nil, 0)
if res != 0 {
return nil
}
var ret = [CChar].init(repeating: 0, count: size + 1)
res = sysctlbyname(name, &ret, &size, nil, 0)
return res == 0 ? String(cString: ret) : nil
}
///Gets an Integer value from the `sysctlbyname` function
static func getInteger<T: FixedWidthInteger>(_ valueName: String) -> T?{
var ret = T()
var size = MemoryLayout.size(ofValue: ret)
let res = sysctlbyname(namePrefix + valueName, &ret, &size, nil, 0)
return res == 0 ? ret : nil
}
#else
///Gets a `String` from `/proc/sys`
static func getString(_ valueName: String) -> String?{
let path = "/proc/sys/" + (namePrefix + valueName).replacingOccurrences(of: ".", with: "/")
var contents = ""
do{
contents = try String(contentsOfFile: path)
}catch let err{
return nil
}
if contents.last == "\n"{
contents.removeLast()
}
return contents
}
///Gets an Integer value from `/proc/sys`
static func getInteger<T: FixedWidthInteger>(_ valueName: String) -> T?{
guard let str = getString(valueName) else { return nil }
return T(str)
}
#endif
///Gets a `Bool` value from the `sysctlbyname` function
static func getBool(_ valueName: String) -> Bool?{
guard let res: Int32 = getInteger(valueName) else{
return nil
}
return res == 1
}
}
So at the end i figured it out on my own, i hope this can be useful to anyone having to do the same thing.
sysctlbyname failing in swift 1.2
The solution is there in the comment in your code: Size is now Int
rather than Uint
in 1.2, so this compiles:
var deviceModelIdentifier: String {
var size : Int = 0
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)!
}
(you can also write var size : size_t = 0
if you prefer)
Error message hints at this when you wade through the unsafe pointer boiler plate:
note: expected an argument list of type '(UnsafePointer< Int8 >,
UnsafeMutablePointer< Void >, UnsafeMutablePointer<Int>,
UnsafeMutablePointer< Void >, Int)'
Get computer informations from Swift
You should only ask one question at a time but I'll try to summarize:
To get the operating system version
ProcessInfo.processInfo.operatingSystemVersionString
To get the machine type will not be so easy. You can get only the Model Identifier AFAIK
MacPro5,1
. You would need to use the terminal commandsysctl hw.model
Processor I think you will need the terminal command as well.
sysctl -n machdep.cpu.brand_string
sysctl -n machdep.cpu.core_count
To get the physical memory. I am not sure if you can get the free memory as well.
ProcessInfo.processInfo.physicalMemory
To use the terminal command in Swift you can do something like:
extension DataProtocol {
var string: String? { String(bytes: self, encoding: .utf8) }
}
extension Process {
static func stringFromTerminal(command: String) -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.launchPath = "/bin/bash"
task.arguments = ["-c", "sysctl -n " + command]
task.launch()
return pipe.fileHandleForReading.availableData.string ?? ""
}
static let processor = stringFromTerminal(command: "machdep.cpu.brand_string")
static let cores = stringFromTerminal(command: "machdep.cpu.core_count")
static let threads = stringFromTerminal(command: "machdep.cpu.thread_count")
static let vendor = stringFromTerminal(command: "machdep.cpu.vendor")
static let family = stringFromTerminal(command: "machdep.cpu.family")
}
Usage:
Process.processor
Getting system uptime in iOS/Swift
As you ask for a pure-Swift solution, I converted the ObjC code from the answer you mentioned Getting iOS system uptime, that doesn't pause when asleep.
func uptime() -> time_t {
var boottime = timeval()
var mib: [Int32] = [CTL_KERN, KERN_BOOTTIME]
var size = strideof(timeval)
var now = time_t()
var uptime: time_t = -1
time(&now)
if (sysctl(&mib, 2, &boottime, &size, nil, 0) != -1 && boottime.tv_sec != 0) {
uptime = now - boottime.tv_sec
}
return uptime
}
// print(uptime())
To make it a bit prettier, we can use sysctlbyname
instead of sysctl
:
// var mib: [Int32] = [CTL_KERN, KERN_BOOTTIME]
sysctlbyname("kern.boottime", &boottime, &size, nil, 0)
Objective-C to Swift conversion for C function
It is not too difficult if one knows two things:
- The C
int
type is a 32-bit integer, this isInt32
in Swift,
notInt
. sizeof()
from C isMemoryLayout<T>.stride
in Swift.
Then we get:
var mib : [Int32] = [ CTL_HW, HW_MEMSIZE ]
var physicalMemorySize: Int64 = 0
var size = MemoryLayout<Int64>.stride
if sysctl(&mib, UInt32(mib.count), &physicalMemorySize, &size, nil, 0) == 0 {
print(physicalMemorySize)
} else {
print("sysctl failed")
}
Capture model identifier for Apple Watch from WatchOS
You never allocate a buffer to receive the machine string.
Change
var machine = CChar()
to
var machine = [CChar](repeating: 0, count: size)
and you should be good to go!
How to determine the current iPhone/device model?
I made this "pure Swift" extension on UIDevice
.
If you are looking for a more elegant solution you can use my µ-framework DeviceKit
published on GitHub (also available via CocoaPods, Carthage and Swift Package Manager).
Here's the code:
import UIKit
public extension UIDevice {
static let modelName: String = {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
func mapToDevice(identifier: String) -> String { // swiftlint:disable:this cyclomatic_complexity
#if os(iOS)
switch identifier {
case "iPod5,1": return "iPod touch (5th generation)"
case "iPod7,1": return "iPod touch (6th generation)"
case "iPod9,1": return "iPod touch (7th generation)"
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4"
case "iPhone4,1": return "iPhone 4s"
case "iPhone5,1", "iPhone5,2": return "iPhone 5"
case "iPhone5,3", "iPhone5,4": return "iPhone 5c"
case "iPhone6,1", "iPhone6,2": return "iPhone 5s"
case "iPhone7,2": return "iPhone 6"
case "iPhone7,1": return "iPhone 6 Plus"
case "iPhone8,1": return "iPhone 6s"
case "iPhone8,2": return "iPhone 6s Plus"
case "iPhone9,1", "iPhone9,3": return "iPhone 7"
case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus"
case "iPhone10,1", "iPhone10,4": return "iPhone 8"
case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus"
case "iPhone10,3", "iPhone10,6": return "iPhone X"
case "iPhone11,2": return "iPhone XS"
case "iPhone11,4", "iPhone11,6": return "iPhone XS Max"
case "iPhone11,8": return "iPhone XR"
case "iPhone12,1": return "iPhone 11"
case "iPhone12,3": return "iPhone 11 Pro"
case "iPhone12,5": return "iPhone 11 Pro Max"
case "iPhone13,1": return "iPhone 12 mini"
case "iPhone13,2": return "iPhone 12"
case "iPhone13,3": return "iPhone 12 Pro"
case "iPhone13,4": return "iPhone 12 Pro Max"
case "iPhone14,4": return "iPhone 13 mini"
case "iPhone14,5": return "iPhone 13"
case "iPhone14,2": return "iPhone 13 Pro"
case "iPhone14,3": return "iPhone 13 Pro Max"
case "iPhone14,7": return "iPhone 14"
case "iPhone14,8": return "iPhone 14 Plus"
case "iPhone15,2": return "iPhone 14 Pro"
case "iPhone15,3": return "iPhone 14 Pro Max"
case "iPhone8,4": return "iPhone SE"
case "iPhone12,8": return "iPhone SE (2nd generation)"
case "iPhone14,6": return "iPhone SE (3rd generation)"
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4": return "iPad 2"
case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad (3rd generation)"
case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad (4th generation)"
case "iPad6,11", "iPad6,12": return "iPad (5th generation)"
case "iPad7,5", "iPad7,6": return "iPad (6th generation)"
case "iPad7,11", "iPad7,12": return "iPad (7th generation)"
case "iPad11,6", "iPad11,7": return "iPad (8th generation)"
case "iPad12,1", "iPad12,2": return "iPad (9th generation)"
case "iPad13,18", "iPad13,19": return "iPad (10th generation)"
case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air"
case "iPad5,3", "iPad5,4": return "iPad Air 2"
case "iPad11,3", "iPad11,4": return "iPad Air (3rd generation)"
case "iPad13,1", "iPad13,2": return "iPad Air (4th generation)"
case "iPad13,16", "iPad13,17": return "iPad Air (5th generation)"
case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad mini"
case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad mini 2"
case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad mini 3"
case "iPad5,1", "iPad5,2": return "iPad mini 4"
case "iPad11,1", "iPad11,2": return "iPad mini (5th generation)"
case "iPad14,1", "iPad14,2": return "iPad mini (6th generation)"
case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)"
case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)"
case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4": return "iPad Pro (11-inch) (1st generation)"
case "iPad8,9", "iPad8,10": return "iPad Pro (11-inch) (2nd generation)"
case "iPad13,4", "iPad13,5", "iPad13,6", "iPad13,7": return "iPad Pro (11-inch) (3rd generation)"
case "iPad14,3", "iPad14,4": return "iPad Pro (11-inch) (4th generation)"
case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch) (1st generation)"
case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch) (2nd generation)"
case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8": return "iPad Pro (12.9-inch) (3rd generation)"
case "iPad8,11", "iPad8,12": return "iPad Pro (12.9-inch) (4th generation)"
case "iPad13,8", "iPad13,9", "iPad13,10", "iPad13,11":return "iPad Pro (12.9-inch) (5th generation)"
case "iPad14,5", "iPad14,6": return "iPad Pro (12.9-inch) (6th generation)"
case "AppleTV5,3": return "Apple TV"
case "AppleTV6,2": return "Apple TV 4K"
case "AudioAccessory1,1": return "HomePod"
case "AudioAccessory5,1": return "HomePod mini"
case "i386", "x86_64", "arm64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))"
default: return identifier
}
#elseif os(tvOS)
switch identifier {
case "AppleTV5,3": return "Apple TV 4"
case "AppleTV6,2": return "Apple TV 4K"
case "i386", "x86_64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))"
default: return identifier
}
#endif
}
return mapToDevice(identifier: identifier)
}()
}
You call it like this:
let modelName = UIDevice.modelName
For real devices it returns e.g. "iPad Pro (12.9-inch) (5th generation)", for simulators it returns e.g. "Simulator iPad Pro (12.9-inch) (5th generation)"
Here's the model references:
- https://theiphonewiki.com/wiki/Models
- https://theiphonewiki.com/wiki/BORD
Related Topics
Uiscrollview with iOS Auto Layout Constraints: Wrong Size for Subviews
Calling Instance Method During Initialization in Swift
How to Add Custom Text in Nsdateformatter's Format String
How to Call Https Url in Uiwebview
Usage of String.Range in Swift 3.0
Does iOS Calendar Support a Url Scheme
Uipickerview: Nsattributedstring Not Available in iOS 7
Programmatically Access Image Assets
Skspritenode Position Changes to 0,0 for No Reason
Running Nsurlsession Completion Handler on Main Thread
Gssendevent - Inject Touch Event iOS
Swift String Escaping When Serializing to JSON Using Codable
How to Open a Link to a PDF with Wkwebview
How to Convert String to Unicode(Utf-8) String in Swift