Command line argument behaviour in macOS 15 after compiling with Xcode 16

I encountered this issue with an app I'm writing that accepts arguments. With some troubleshooting I've determined that this is an inherent behaviour in how Xcode 16 compiles SwiftUI apps and how macOS 15 launches them.

The issue: Launching the app as open /Applications/AppName.app --args --arg1 --arg2 --arg3 etc should allow the app to process the arguments as CommandLine.arguments and this is still the case. How the app sees arguments is unchanged and doesn't matter if you use CommandLine.arguments or swift argument parser or don't have arguments at all. This will affect any SwiftUI app as I'll demonstrate below.

The problem is that if you use a mix of arguments as --arg value pairs or --arg as a flag, then depending on the order the arguments are provides, the app won't launch properly. The icon will appear in the dock but no window appears until you click the icon in the dock. (BTW, having "Application is agent (UIElement)" set to YES in the Info.plist makes this task rather difficult.)

In testing if you use all flags, it's fine. if the flags are in pairs, it's fine. if you have one flag and then a --arg value pair, you will see the issue. If you reverse the order so the flag is after then it works fine.

How to replicate: On macOS 15 and Xcode 16

  • Open Xcode
  • Create a new macOS App (called demoapp in my example)
  • Select SwiftUI as the interface
  • Build

That it. Don't add anything and just build the boilerplate hello world app that Xcode makes for you. Once that's built, cd to your /Build/Products/Debug/ directory in terminal and try the following (this happens if you build for release as well):

note, the app window will display when you click the icon in the dock, just not on initial launch

# three single arguments
open ./demoapp.app --args --foo --bar --baz
# App window displays as expected

# one single argument, one arg value pair
open ./demoapp.app --args --foo --bar baz
# The app window will not appear.

# same arguments as before but the single argument is after the arg value pair 
open ./demoapp.app --args --bar baz --foo
# App window displays as expected

# arg[1] without `-` or `--` prefix
open ./demoapp.app --args foo --bar --baz
# The app window will not appear. 

# arg[1] and arg [2] without prefix
open ./demoapp.app --args foo bar --baz
# The app window will not appear.

# single - in front of the first two arguments
open ./demoapp.app --args -foo -bar baz
# The app window will not appear.

# single - in front of the first three arguments
open ./demoapp.app --args -foo -bar -baz bob
# App window displays as expected

No idea what is going on but I suspect macOS does some pre-processing before launching the app, for example you can do stuff like open /Applications/SomeApp.app --args -AppleLanguages '(de)' to run using a specific language. I presume the OS is pre-processing arguments before launching the app proper.

If I compile the app using Xcode 15.4 then this issue is not present. Also Apps compiled with Xcode 16 do not exhibit the issue on macOS 14 or earlier. It's a specific Xcode 16, macOS 15 thing in the way the app is compiled that makes it behave this way.

I hope I've explained it correctly, but it's very easy to replicate. I filed a feedback for it (under a different apple account), FB15577018.

Any insight into what's going on here would be helpful. Also if there's any compiler flags I could be setting. In my actual project, I'm not making any other changes. The same code compiled under Xcode 16 (.0 or .1RC) behaves differently to Xcode 15.4.

This is still an issue in Xcode 16.3 and macOS 15.4.1. Also no activity on my feedback.

Searching for similar cases on google returns this post as the first hit so I'm guessing I'm the only one with this issue :/. Unfortunately I can't move my compile workflow to macos 15/xcode 16 with the current code and re-factoring to use something else like swift argument parser is going to take me some time.

I followed your instructions to the letter and it worked perfectly every time.

weird - only reason I revisited it is I set up a new mac just this week from scratch and was experiencing the same problem, figuring it wasn't something specific to my old setup.

Thanks for the reply though @Etresoft and confirming it's not an issue for you. If that's the case I might try installing just macOS and Xcode and nothing else and see if I can increment my way towards the issue. For context, my device is corporate owned so has MDM enrolment, AV, and other paraphernalia so perhaps it's a combination of something that's impacting how apps are being launched. I'll do some more testing.

It would help if you could clarify some things.

First of all, passing arguments to an app is very unusual. I support it in one of my apps, but I'm pretty sure that virtually no one has ever used that feature. There was also a recent thread here where an Apple engineer suggested that command line operation may be incompatible with linkage of UI frameworks.

Add to that the fact that you are doing something with UIElement.

Plus, you are running all this through the "open" tool. Does it behave the same if you directly launch the executable with your arguments?

First of all, passing arguments to an app is very unusual.

It is but not totally out of the ordinary. I'm porting that side of things to a dedicated cli tool but I'm also learning about xpc, notifications etc at the same time. I would like to be more "mac arsed" in my app development. Insert comment about tech debt here. That said, --args is a feature available in the open command and CommandLine.arguments is a property available to macOS apps. The expectation is that those should operate consistently. I'm also aware that there is a potential conflict with things like using -AppleLanguages to change the language an app is launched in so there is some pre-processing going on by the OS that is parsed before an app is launched fully but again, --args is available to be used, whatever macOS is doing should be able to handle that and just pass through arguments array into the app.

Plus, you are running all this through the "open" tool. Does it behave the same if you directly launch the executable with your arguments?

Exact same behaviour. using open or calling the executable directly with arguments has the exact same effect.

I did some further testing though. I created a new macOS 15 VM, installed Xcode 16 and nothing else. Creating a new project and compiling the boilerplate SwiftUI app adding nothing else and I can re-create the behaviour:

# three single arguments
open ./demoapp.app --args --foo --bar --baz
./demoapp.app/Contents/MacOS/demoapp --foo --bar --baz
# App window displays as expected
 
# one single argument, one arg value pair
open ./demoapp.app --args --foo --bar baz
./demoapp.app/Contents/MacOS/demoapp --foo --bar baz
# The app window will not appear.

and the same with the rest of the examples. TBC, in the second example, the app launches, but the main window does not appear until I click on the icon for it in the dock. Adding NSApp.activate(ignoringOtherApps: true) has no effect as if the app window doesn't exist.

edit: just adding in that I'm using a SwiftUI app in my demo but the same behaviour appears if using AppKit lifecycle. My gut tells me it's something with how macOS 15 is pre-processing arguments, looking for whatever, and how Xcode 16 compiles those apps. apps compiled in Xcode 15 (macos 14) don't have any of these issues, but I don't know enough about the app lifecycle on macOS to dig deeper and understand what's going on. Ultimately the fix is I re-write how I accept/process arguments but I'm not quite there yet, hence I have a dev box stuck on macOS 14 for the time being.

It is but not totally out of the ordinary.

It is totally out of the ordinary.

I would like to be more "mac arsed" in my app development.

I don't know what that means.

It might be helpful to remember that the entirety of the macOS platform is an outlier. It constitutes 8% of Apple's sales, and probably a smaller percentage of profit. Apps run on iOS. If you're flush with cash and have time to burn, maybe you can play around and port your app to the Mac. But ain't nobody going to be using any command-line arguments.

I'm also aware that there is a potential conflict with things like using -AppleLanguages to change the language an app is launched in so there is some pre-processing going on by the OS that is parsed before an app is launched fully but again

That's a debugging flag. The Cocoa/AppKit frameworks do some parsing of command line arguments. However, they do that as part of NSApplicationMain(), which takes over completely. There also exists an NSApplicationLoad() that command-line apps would typically call so that they can use most Cocoa/AppKit system functionality, or maybe construct their own run loop.

--args is available to be used, whatever macOS is doing should be able to handle that and just pass through arguments array into the app.

--args is just an argument to the "open" tool. And it works fine, as do command line arguments if you run an app directly. I don't know what problem you're having, but it isn't any kind of system-wide problem and isn't related to any Xcode version.

I don't want to discourage you. Clearly there is something very wrong with your setup. It would probably be worthwhile to find out what's causing the problem. Command line arguments are irrelevant. But there is a risk that whatever is going wrong could affect some important functionality.

Virtual machines are useful for testing code. But I wouldn't recommend installing Xcode in one. Xcode is for a real machine. But also, once you install Xcode on a real machine, it isn't a real machine anymore. It's now a "developer device" whose behaviour may not be the same as an end-user's device. Virtual Machines can be useful as a quick-and-easy end-user, non-developer device. Ideally, you would also test on a real machine that has never had Xcode installed.

You had mentioned that "my device is corporate owned so has MDM enrolment, AV, and other paraphernalia". I strongly encourage you to focus your attention there. Don't forget the network either. Your corporate network is probably also non-standard.

Apps run on iOS.

All this time developing on mac and for naught, as apps don't run on macOS. /s

maybe you can play around and port your app to the Mac

It's.....already is a mac app 🤔

But ain't nobody going to be using any command-line arguments.

FWIW, my app's primary mode of interaction is via command line arguments due to what it does and the audience it targets (scripted interactions on managed devices), hence why this issue is of particular interest to me.

I don't want to discourage you.

You are. I appreciate your response and willingness to spend time trying to understand my issue but your last reply offers nothing constructive and tries to dismiss what I'm seeing as irrelevant.

I fully understand this is an edge case. By definition edge cases are not common, but that doesn't invalidate what I'm trying to achieve for my app.

I thank you for your time but I think I have already used up the usefulness of this discussion space as clearly I'm developing for the wrong platform.

Command line argument behaviour in macOS 15 after compiling with Xcode 16
 
 
Q