Catalyst: determine the device information when running on Mac

When I've tried to use UIDevice on my Mac running my Catalyst application, testing code

   UIDevice *d=UIDevice.currentDevice;
    for (NSString *k in @[@"name", @"systemName", @"systemVersion", @"model", @"localizedModel"])
        NSLog(@"%@ -> %@", k, [d valueForKey:k]);

to my great surprise I am getting

name -> iPad
systemName -> iPadOS
systemVersion -> 26.3
model -> iPad
localizedModel -> iPad

What the. How do I determine the real values? Thanks!

Answered by DTS Engineer in 874075022
HomeKit API available amongst the native macOS APIs

Hmmm, yeah, that certainly seems to be the case. How weird. I don’t support HomeKit, so I’m gonna ask DTS’s resident expert if they have any context for that.

Anyway, given that your app is focused on HomeKit, that definitely forces you to use Catalyst.

just wanted to save it for possible further interest

OK. Assuming that you’re only saving it locally. If you’re uploading it somewhere, comments like that definitely set off privacy alarm bells |-:

Anyway, with that context let’s look at each of these properties.


The name property returns the user-assigned device name. Honestly, I don’t think you should capture this because it’s privacy sensitive. In many cases it’s something like “Eric’s MacBook”.

In this respect, Mac Catalyst follows iOS, in that it returns a placeholder unless you apply for and are granted access by Apple. See the discussion here.

This restriction is not enforced for non-Catalyst code, so it’s possible to get this value without the managed capability on macOS. If you think that’s absolutely necessary, let me know and I can outline your options.


You don’t need the systemName property because there’s only one meaningful value for a Mac Catalyst, macOS.


The systemVersion you get back is pretty reasonable, given that:

  • On macOS 26 and later, the versions are the same.
  • On older systems you can map the Catalyst version to the macOS version in a straightforward fashion.

If you want more details, you can call uname:

var n = utsname()
let success = uname(&n) >= 0
guard success else { … handle error … }
let version = withUnsafePointer(to: n) { nPtr in
    String(cString: nPtr.pointer(to: \.version.0)!)
}
print(version)
// -> Darwin Kernel Version 25.2.0: Tue Nov 18 21:09:41 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T6031

This returns macOS info on macOS, even when you’re in a Mac Catalyst app. It also returns a similar level of detail on iOS.

However, if you think it’s absolutely necessary to get the macOS version, let me know because you do have options.


The model property isn’t particularly useful in the context of the Mac. Rather, most folks track the low-level model value [1]. For example:

% sysctl hw.model
hw.model: Mac15,11

Or in code:

var modelBuf = [CChar](repeating: 0, count: 256)
var modelBufCount = modelBuf.count
let success = sysctlbyname("hw.model", &modelBuf, &modelBufCount, nil, 0) >= 0
guard success else { return }
modelBuf.removeLast(modelBuf.count - modelBufCount)
let model = String(cString: modelBuf)
print(model)

For the localizedModel property, ideally you’d record values like “MacBook Pro” or “Mac mini”. Getting such values on the Mac is tricky. I think it’d be better for you to limit yourself to the low-level model value, at least for the moment.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] This string dates back to Open Firmware on PowerPC-based Macs. There’s been two CPU architecture changes since then O-:

Thanks for the post, what target are you running the code?

On the target does it say "My Mac (Designed for iPad)"

Can you provide the focused simple project and how is configure it here?

That'll help us better understand what's going on. If you're not familiar with preparing a test project, take a look at Creating a test project.

Thanks,

Albert Pascual
  Worldwide Developer Relations.

Thanks!

If I get the “target” thing right, it says “My Mac (Mac Catalyst)”. There's no other option; the selection looks like this ... hm, there's no option here to paste a pic? Darn, like this: https://ocs.cz/CD/run-options.jpg

I'll prepare the test project soon, pbbly in a couple of hours, am a bit at the busy side :)

Being busy is good, appreciate your time in this one, looking forward to your focused sample when available.

Albert Pascual
  Worldwide Developer Relations.

Thanks again :)

Test please at your leisure at your side this project: https://ocs.cz/CD/catalyst_test.zip

Note: my application is intended primarily for macOS, should be able to run also with lower priority, essentially as a side-effect, on iPadOS. Thus I believe “Catalyst” to be a much better destination than “Designed for iPad”, or am I wrong here?

Thanks for this, yes, very interesting, may I ask you to file a bug with that project?

Well, looks like we only need this part:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    UIDevice *d=UIDevice.currentDevice;
    for (NSString *k in @[@"name", @"systemName", @"systemVersion", @"model", @"localizedModel", @"userInterfaceIdiom"])
        NSLog(@"%@ -> %@", k, [d valueForKey:k]);
    switch (d.userInterfaceIdiom) {
        case UIUserInterfaceIdiomUnspecified: NSLog(@"UIUserInterfaceIdiomUnspecified"); break;
        case UIUserInterfaceIdiomPhone: NSLog(@"UIUserInterfaceIdiomPhone"); break;
        case UIUserInterfaceIdiomPad: NSLog(@"UIUserInterfaceIdiomPad"); break;
        case UIUserInterfaceIdiomTV: NSLog(@"UIUserInterfaceIdiomTV"); break;
        case UIUserInterfaceIdiomCarPlay: NSLog(@"UIUserInterfaceIdiomCarPlay"); break;
        case UIUserInterfaceIdiomMac: NSLog(@"UIUserInterfaceIdiomMac"); break;
        case UIUserInterfaceIdiomVision: NSLog(@"UIUserInterfaceIdiomVision"); break;
        default: NSLog(@"Idiot unknown");
    }
    exit(0); // no need to run on

If you have any questions about filing a bug report, take a look at Bug Reporting: How and Why?

Albert Pascual
  Worldwide Developer Relations.

may I ask you to file a bug with that project?

Before you do that, I’d like to clarify what you mean by this:

How do I determine the real values?

What specific information are you looking for here? And what do you plan to do with that information?

This matters because Mac Catalyst is returning values that make sense in the iOS-ish environment that’s expected by such apps. It is possible to get ‘real’ values, but the best way to do that depends on your specific setup.

For example, the systemName property is uninteresting in a Mac Catalyst app because the real system name is macOS. So you can do this [1]:

let systemName: String
#if targetEnvironment(macCatalyst)
    systemName = "macOS"
#else
    systemName = device.systemName
#endif

However, that’s just one of these properties. The best path for the other properties varies based your the specific property and your ultimate goal.


Also, you wrote:

my application is intended primarily for macOS, should be able to run with priority, essentially as a side-effect, on iPadOS

Given that, I’m not sure Mac Catalyst is your best option, because it means your Mac app, which is your primary focus, will end up being limited by Mac Catalyst. If I were in your shoes I’d create a multiplatform SwiftUI app. That makes it easy to share code between platforms while having each app be native on its respective platform, allowing it to access all of the platform’s services.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Sorry this in in Swift; that’s the project I had lying around. For Objective-C, use TARGET_OS_MACCATALYST.

Thanks, Quinn!

What specific information are you looking for here?

Well ... information of the device and operating system the code really runs on would be sort of nice. It's pretty weird to ask the code which runs on Mac for the device it runs on and get “iPad”.

I could understand this when running as “Designed for iPad”, in which case the code might really need to be lied to, for it was designed for iSomething originally.

But in the Catalyst mode, where the code is designed for Mac, it seems really at the strange side.

And what do you plan to do with that information?

At this moment, I just wanted to save it for possible further interest, along with other things my application stores (see please below).

Currently the only practical part would be to determine whether I can store my data into any file in any folder (as on Mac), or whether I should stick with Application Support sub-folders (as on iWhatever).

Given that, I’m not sure Mac Catalyst is your best option

Well the main purpose of my application is to observe the characteristics of some HomeKit devices and save their value changes along with timestamps. To these stored data I wanted to add the information on which device this happened, purely for possible further interest (most probably nothing more than “recorded on XXX” :))

Do please correct me if I am wrong and if I overlook something of importance, but I understand there is, triple alas, no HomeKit API available amongst the native macOS APIs. Thus — far as I got it right — to write a macOS HomeKit application, I am, alas, forced to stick with Catalyst.

HomeKit API available amongst the native macOS APIs

Hmmm, yeah, that certainly seems to be the case. How weird. I don’t support HomeKit, so I’m gonna ask DTS’s resident expert if they have any context for that.

Anyway, given that your app is focused on HomeKit, that definitely forces you to use Catalyst.

just wanted to save it for possible further interest

OK. Assuming that you’re only saving it locally. If you’re uploading it somewhere, comments like that definitely set off privacy alarm bells |-:

Anyway, with that context let’s look at each of these properties.


The name property returns the user-assigned device name. Honestly, I don’t think you should capture this because it’s privacy sensitive. In many cases it’s something like “Eric’s MacBook”.

In this respect, Mac Catalyst follows iOS, in that it returns a placeholder unless you apply for and are granted access by Apple. See the discussion here.

This restriction is not enforced for non-Catalyst code, so it’s possible to get this value without the managed capability on macOS. If you think that’s absolutely necessary, let me know and I can outline your options.


You don’t need the systemName property because there’s only one meaningful value for a Mac Catalyst, macOS.


The systemVersion you get back is pretty reasonable, given that:

  • On macOS 26 and later, the versions are the same.
  • On older systems you can map the Catalyst version to the macOS version in a straightforward fashion.

If you want more details, you can call uname:

var n = utsname()
let success = uname(&n) >= 0
guard success else { … handle error … }
let version = withUnsafePointer(to: n) { nPtr in
    String(cString: nPtr.pointer(to: \.version.0)!)
}
print(version)
// -> Darwin Kernel Version 25.2.0: Tue Nov 18 21:09:41 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T6031

This returns macOS info on macOS, even when you’re in a Mac Catalyst app. It also returns a similar level of detail on iOS.

However, if you think it’s absolutely necessary to get the macOS version, let me know because you do have options.


The model property isn’t particularly useful in the context of the Mac. Rather, most folks track the low-level model value [1]. For example:

% sysctl hw.model
hw.model: Mac15,11

Or in code:

var modelBuf = [CChar](repeating: 0, count: 256)
var modelBufCount = modelBuf.count
let success = sysctlbyname("hw.model", &modelBuf, &modelBufCount, nil, 0) >= 0
guard success else { return }
modelBuf.removeLast(modelBuf.count - modelBufCount)
let model = String(cString: modelBuf)
print(model)

For the localizedModel property, ideally you’d record values like “MacBook Pro” or “Mac mini”. Getting such values on the Mac is tricky. I think it’d be better for you to limit yourself to the low-level model value, at least for the moment.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] This string dates back to Open Firmware on PowerPC-based Macs. There’s been two CPU architecture changes since then O-:

Catalyst: determine the device information when running on Mac
 
 
Q