Xcode 9: A big step forward, and some important steps back

If you’re still wondering whether to update to Xcode version 9, or have already updated and are wondering whether to start moving to Swift 4, then wonder no further. Version 9 is far superior. Neither does it require you to be running High Sierra, just Sierra 10.12.6 or later.

Xcode 8.3.3 reminds me of a drunken elephant: huge, lots of potential, but whenever you wanted it to do something, it imposed a great deal of resistance. Most of its better features, like autocomplete, were excellent much of the time, but under pressure they tended to crack. But its biggest problem for me was its macOS dependence. I could only get it to built code for Sierra, although in its beta days it had apparently built apps to run on El Capitan.

The headline for Xcode 9 is that it runs on both Sierra and High Sierra, and you can opt to build code which runs (it claims) on Macs running OS X 10.6 and later.

When you build for older systems, it seems to use the right interfaces. For example, if your code calls FileManager’s homeDirectoryForCurrentUser, which only appeared in macOS 10.12, and your app requires 10.11, you’ll be informed of the error, but not pointed in the direction of a solution. In this case, using something like
let homeDirURL = URL(fileURLWithPath: NSHomeDirectory())
should work more generally.

As to how reliable its support for OS X prior to Sierra is, I’m still waiting to hear from those trying to run my free apps on El Capitan, but no one has yet asked for their money back.

Before opening any project in Xcode 9, I made archival copies of each of them, so that you can always revert to your 8.3.3 code, if you need to.

Open an existing Swift 3.1 project in Xcode 9 and it gets converted to Swift 3.2, which should be both transparent and free of pain. My first step on each occasion is to set the project deployment target to macOS 10.12, and for the project format to be Xcode 8 compatible.


I then increment the version and/or build as appropriate, refresh the signing, and set the target’s Deployment Target to macOS 10.12 too.


By this stage, Xcode will have performed a silent build, and you should have at least two issue warnings, on top of any from your code. The two issues for the whole project will be updating to recommended settings, and conversion to Swift 4. Step through these in order.


The first enables a bunch of recommended warnings in the build settings. Select the warning, and perform the changes.

This may spawn additional warnings, and it is worth performing a manual build at this stage to elicit them. Once you’re happy, and your app is looking happy too, select conversion to Swift 4.


Select the target in the first dropdown sheet, and click on the Next button,


Minimal interference with @objc inference is recommended, so just click on the Next button in the next sheet.


You’ll then be invited to view the help notes, and to press on with the code conversion.


Xcode then displays its proposed changes to your source code to complete the conversion. These amount to a series of interface changes like those shown here, where NSDocument’s func autosavesInPlace() turns into a var returning the boolean, and so on.


Other changes spotted included NSAlertStyle.critical becoming NSAlert.Style.critical – the sort of thing which you might spend ages trying to correct manually.


Once you’re happy with the proposed changes to your source code, click on the Save button to fix those changes in your source files.


You’ll then see a new warning about the use of Swift 3 @objc inference. If you’ve got outstanding warnings about these, you’ll need to look carefully at the app help. At the moment, searching for solutions on the internet is not likely to be much good, as Swift 4 is so new. I couldn’t find any warnings, and a quick build and test didn’t raise any suspicions either.


My next step then was to look at the build settings for the target. At the foot of those is confirmation that the code is now to be compiled as Swift 4.0, and a little way up from there I set the Swift 3 @objc inference from On to Off.

One more build and a thorough test should be sufficient to confirm that your source code has been successfuly migrated to Swift 4.0.

For small, simple scripting-type apps like most of my utilities here, moving them to Swift 3.2 in Xcode 9 is almost effortless. Adding El Capitan support can be easy too, unless your code uses a lot of 10.12-specific features. Migrating from Swift 3.2 to 4 is the big jump, but Apple has done a great deal to assist developers.

Xcode 9 is a very big step forward, and its support for earlier versions of macOS/OS X is a great help to those coding in Swift.