Category Archives: Apple

Xcode’s Secret Performance Tests

I was inspired today, by a question from another developer, to dig into Xcode’s performance testing. This developer had observed that XCTestCase exposes a property, defaultPerformanceMetrics, whose documentation strongly suggests can be used to add additional performance metrics:

This method returns XCTPerformanceMetric_WallClockTime by default. Subclasses of XCTestCase can override this method to change the behavior of measureBlock:.

If you’re not already familiar, the basic approach to using Xcode’s performance testing infrastructure is you add unit tests to your project that wrap code with instructions to measure performance. From the default unit test template:

func testPerformanceExample() {
	// This is an example of a performance test case.
	self.measure {
		// Put the code you want to measure the time of here.

Depending on the application under test, one can imagine all manner of interesting things that might be useful to tabulate during the course of a critical length of code. As mentioned in the documentation, “Wall Clock Time” is the default performance metric. But what else can be measured?


At least, according to any header files, documentation, WWDC presentations, or blunt Googling that I have encountered. There is exactly one publicly documented Xcode performance testing metric, and it’s XCTPerformanceMetric_WallClockTime.

I was curious whether supporting additional, custom performance metrics might be possible but under-documented. To test this theory, I added “beansCounted” to the list of performance metrics returned from my XCTestCase subclass. For some reason I couldn’t get Swift to accept the XCTPerformanceMetric pseudo-type, but it allowed me to override as returning an array of String:

override static func defaultPerformanceMetrics() -> [String] {
	return ["beansCounted"]

When I build and test, this fails with a runtime exception “Unknown metric: beansCounted”. The location of an exception like this is a great clue about where to go hunting for information about whether an uknown metric can be made into a known one! If there’s a trick to implementing support for my custom “beansCounted” metric, the answer lies in the method XCTestCase’s “measureMetrics(_: automaticallyStartMeasuring: forBlock:)”, which is where the exception was thrown.

By setting a breakpoint on this method and stepping through the assembly in Xcode, I can watch as the logic unfolds. To simplify what happens: first, a list of allowable metrics is computed, and then the list of desired metrics is iterated. If any metric is not in the list? Bzzt! Throw an exception.

I determined that things are relatively hardcoded such that it’s not trivial to add support for a new metric. I was hoping I could implement some magic methods in my test case, like “startMeasuring_beansCounted” and “stopMeasuring_beansCounted”

but that doesn’t appear to be the case. The performance metrics are supported internally by a private Apple class called XCTPerformanceMetric, and the list of allowable metrics is derived from a few metrics hardcoded in the “measureMetrics…” method:

  • “”
  • “”
  • “”
  • “”

As well as a bunch of others exposed by a private “knownMemoryMetrics” method:

  • “”
  • “”
  • “”
  • “”
  • “”
  • “”
  • “”
  • “”
  • “”
  • “”

How interesting! There are a lot more metrics defined than the single “wall clock time” exposed by Apple. So, should we use them? Official answer: no way! This is private, unsupported stuff, and can’t be relied upon. Punkass Daniel Jalkut answer? Why not? They’re your tests, and your the only one who will get hurt if they suddenly stop working. In my opinion taking advantage of private, undocumented system behavior for private, internal gain is much different than shipping public software that relies upon such undocumented behaviors.

I modified my unit test subclass to return a custom array of tests based on the discoveries above, just to test a few:

override static func defaultPerformanceMetrics() -> [String] {
	return [XCTPerformanceMetric_WallClockTime, "", "", ""]

The tests build and run with no exception. That’s a good sign! But these “secret peformance tests” are only useful if they can be observed and tracked the way the wall clock time can be. How does Xcode hold up? I made my demonstration test purposefully impactful on some metrics:

func testPerformanceExample() {
	self.measure {
		for _ in 1..<100 {
			print("wasting time")
		let _ = malloc(3000)

Now when I build and test, look what shows up in the Test navigator’s editor pane:

Screenshot of performance metrics after reducing the size of allocations and length of run.

Look at all those extra columns! And if I click the “Set Baselines…” button, then tweak my function to make it substantially less performant:

func testPerformanceExample() {
	self.measure {
		for _ in 1..<10000 {
			print("wasting time")
		let _ = malloc(300000)

Now the columns have noticably larger numbers:

Screenshot of Xcode's test results after running tests with

But more importantly, the test fails:

Screenshot of test errors generated by failing to meet performance baselines.

I already mentioned that by any official standard, you should not take advantage of these secret metrics. They are clearly not supported by Apple, may be inaccurate or have bugs, and could outright stop working at any time. I also said that, in my humble opinion, you should feel free to use them if you can take advantage of them. The fact that they are supported so well in Xcode probably implies that groups internal to Apple are using them and benefiting from them. Your mileage may vary.

The only rule is this: if Apple does do anything to change their behavior, or you otherwise ruin your day by deciding to play with them, you shouldn’t blame Apple, and you can’t blame me!


Accessible Frames

I love the macOS system-wide dictionary lookup feature. If you’re not familiar with this, just hold down the Control, Command, and D keys while hovering with the mouse cursor over a word, and the definition appears. What’s amazing about this feature is it works virtually everwyhere on the system, even in apps where the developers made no special effort to support it.

Occasionally, while solving a crossword puzzle in my own Black Ink app, I use this functionality to shed some light on one of the words in a clue. As alluded to above, it “just works” without any special work on my part:

Screen shot of Black Ink's interface, with a highlighted word being defined by macOS system-wide dictionary lookup.

Look carefully at the screenshot above, and you can see that although the dictionary definition for “Smidgen” appears, it seems to have highlighted the word in the wrong location. What’s going on here?

The view in Black Ink that displays the word is a custom NSTextField subclass called RSAutosizingTextField. It employs a custom NSTextFieldCell subclass in order to automatically adjust the font size and display position to best “fill up” the available space. In short: it behaves a lot like UITextField on iOS.

To achieve this behavior, one of the things my custom cell does is override NSTextFieldCell’s drawingRect(forBounds:). This allows me to take advantage of most of NSTextField’s default drawing behavior, but to nudge things a bit as I see fit. It’s this mix of customized and default behaviors that leads to the drawing bug seen above. I’ve overridden the drawing location, but haven’t done anything to override the content hierarchy as it’s reflected by the accessibility frameworks.

What do the accessibility frameworks have to do with macOS system-wide dictionary lookup? A lot. Apparently it’s the “accessibilityFrame” property that dictates not only where the dictionary lookup’s highlighting will be drawn, but also whether the mouse will even be considered “on top of” a visible word or not. So in the screenshot above, if the mouse is hovering over the lower half of the word “Smidgen”, then the dictionary lookup doesn’t even work.

The fix is to add an override to NSTextField’s accessibilityFrame method:

public override func accessibilityFrame() -> NSRect {
	let parentFrame = super.accessibilityFrame()
	guard let autosizingCell = self.cell as? RSAutosizingTextFieldCell else { return parentFrame }

	let horizontalOffset = autosizingCell.horizontalAdjustment(for: parentFrame)

	// If we're flipped (likely for NSTextField, then the adjustments will be inverted from what we
	// want them to be for the screen coordinates this method returns.
	let flippedMultiplier = self.isFlipped ? -1.0 as CGFloat : 1.0 as CGFloat
	let verticalOffset = flippedMultiplier * autosizingCell.verticalAdjustment(for: parentFrame)

	return NSMakeRect(parentFrame.origin.x + horizontalOffset, parentFrame.origin.y + verticalOffset, parentFrame.width, parentFrame.height)

Effectively I take the default accessibility frame, and nudge it by the same amount that my custom autosizing text cell is nudging the content during drawing. The result is only subtly difference, but makes a nice visual refinement, and a big improvement to usability:

Screen shot of dictionary lookup UI with properly aligned word focus.

I thought this was an interesting example of the accessibility frameworks being leveraged to provide a service that benefits a very wide spectrum of Mac users. There’s a conventional wisdom about accessibility that emphasizing the accessibility of apps will make the app more usable specifically for users who take advantage of screen readers and other accommodations, but more generally for everybody who uses the app. This is a pretty powerful example of that being the case!

App Store Upload Failures

I’ve been running into failures to connect to iTunes Connect through Application Loader. Others corroborate similar problems uploading through Xcode. The nut of the problem comes down to a failure to authenticate a specific Apple ID. The failure string is “Unable to process authenticateWithArguments request at this time due to a general error”:

Image of the Sign In window for Application Loader showing a failure message

Whatever is going on, it’s somewhat sporadic. It started failing for me about 48 hours ago, and briefly started working again yesterday, but only for a few hours. Changes of network, computer, even clearing out all the app preferences and data for Application Loader, seem to have no impact on the issue.

I’ve filed a bug with Apple (Radar #36435867), and discovered a workaround you can use in a pinch: add another Developer ID to your team. I was able to grant admin privileges to a second Apple ID I control, and use it to log in and upload to my account. I’m not sure if this workaround requires a “company” style developer account, or if it can also be used for individual accounts.

Xcode 9 Signing Workarounds

I wrote on Monday about issues with Xcode 9 relating to code signing. Although the gist of that post involved sandboxed Mac applications that launch sandboxed child processes, the fundamental issue is a bit broader: Xcode 9 adds a “” entitlement to any binary it signs. For the majority of developers, this is probably not an issue, because the entitlement is removed when an Xcode archive is exported for distribution. Most developers, and particularly iOS developers, use Xcode archives.

For folks who don’t, side effects of this additional entitlement include, but may not be limited to:

  1. Inability to launch sandboxed child processes.
  2. Rejection from the Mac App Store.
  3. Unknown consequences of shipping with an unintended entitlement.

So, if you’re a developer who doesn’t use archives, what are your options? I’ve come up with four workarounds, and I present them here, roughly sorted by advisability and level of tedium:

  1. Use Xcode 8. The simplest solution is to not upgrade to Xcode 9 unless and until you need to. Xcode 8’s signing process does not impose the unintended entitlement, so there is no risk of shipping a product that has it, unless you add it yourself. The downside to sticking with Xcode 8 is you won’t enjoy any of the new features of Xcode 9, you’ll have to work to support either Swift 4, macOS 10.13, or iOS 11 SDK features in your app.

  2. Manually re-sign the built-product. Code signing is code signing, and you’re free to sign anything you like to suit your needs, using the “codesign” command line tool. It frankly sounds like a pain in the neck to recursively re-sign every binary in the app bundle, ensuring that the suitable entitlements (minus the unwanted one) are preserved, but I’m sure it can be done.

  3. Use Xcode archives. It strikes me as a little obnoxious to have to use Xcode archives when they don’t offer any added benefits for my dibstrution workflow. But as a long term solution, this is probably the safest bet. The new behavior in Xcode 9 strongly suggests that Apple expects most developers to use archives, and joining the crowd is usually a good idea when it comes to avoiding trouble with Apple’s developer tools.

    If you are using Xcode archives for the first time, particularly with a complex project, you might discover that the resulting archives are not suitable for exporting a signed application. If you get a “Generic Xcode Archive” after running Build -> Archive, you know you’ve got a problem. By default the archive process builds all targets with an “install” option, rendering their built products into a file hierarchy that will be used to build the archive. If your project includes helper apps, for example, they will be “installed” alongside your main app, resulting in a generic archive of two apps, instead of the expected archive of a single app.

    The solution for this problem is to ensure that the “SKIP_INSTALL” build setting is set to YES for any such helper app. Just archive your main app, export the “Built Products” from the resulting archive, and look at the file hierarchy to determine whether you have subtargets that need to have installation disabled.

  4. Hack Xcode 9. In a hurry to ship an update to your app, and you’ve only got Xcode 9 handy? It turns out the imposition of this “” entitlement is controlled by a single property list file inside Xcode’s application bundle. As a test, I edited the file:

    It contains a single entitlement, the one that’s causing our grief. I deleted the entitlement from the list, saved the file, and relaunched Xcode. After doing so, everything is “back to normal.”

    I can’t strongly encourage you to hack your copy of Xcode because I don’t know what the consequences might be. “It seems fine,” but you’re on your own if you decide to do this.

This small change in Xcode 9 causes a lot of unexpected grief for folks who don’t use Xcode archives. I am curious to know how widespread the problem is, and enthusiastic to get the word out about it so that affected folks can work around the problem, or at least be aware of it. Myself, I’ll probably end up adopting the workaround of using Xcode archives, but I’m hopeful that Apple will see the merit of providing an option in an update to Xcode 9 that supports disabling the addition of this entitlement without archiving and exporting a built product.

Sandbox Inheritance Tax

I ran into a subtle bug with Xcode 9 that I think is worth sharing. Specifically, this bug affects Mac applications that:

  1. Are sandboxed.
  2. Launch a sandboxed subprocess with NSTask (or posix_spawn).
  3. Configure the subprocess to inherit the parent’s sandbox.

When such an app is compiled with Xcode 9, the subprocess will crash whenever the parent process launches it. A canonical example of something that might suffer from this problem is a bundled crash-monitor. I embed one with my apps to keep an eye on the running status of the parent process, and to present a crash-reporting interface to users if the host app terminates prematurely. When I build and run my app with Xcode 9, the bundled crash monitor dies instantly upon being launched.

It took me a while to realize that the subprocess is dying because it fails to satisfy the contract for inheriting a sandbox. From Apple’s “Enabling App Sandbox Inheritance“:

To enable sandbox inheritance, a child target must use exactly two App Sandbox entitlement keys: and If you specify any other App Sandbox entitlement, the system aborts the child process.

Well, that’s funny because my child process does specify only those two keys, but the system is aborting it anyway. It turns out that Xcode 9 is inserting a third entitlement without my permission. Clicking on the detail of the “Process Product Packaging” build phase in Xcode’s log navigator, I can see that there are three entitlements for my target:

Xcode build log detail showing the wrong entitlements.

When my subprocess is launched, the system sees that extra “” entitlement in the context of “”, and unceremoniously crashes my the child process.

I’m not sure what Apple’s reasoning is for imposing this entitlement on sandboxed targets, but it appears to be doing so across the board, for literally every sandboxed target in my app. I confirmed that all of my apps, XPC processes, helper tools, etc., are all getting this bonus entitlement.

I searched Xcode’s files, and discovered the entitlement listed in this file inside the Xcode app bundle:


Putting aside the question of whether it’s appropriate for Xcode to surreptitiously add entitlements that are not specified by the developer’s own list of permissions, the addition of the entitlement for these particular targets, ones that inherit their parent’s sandbox, turns out to be a fatal move.

Ideally I would be able to work around this by adding a custom build phase to manually tweak the generated entitlements file, removing the unwanted key. But the “Process Product Packaging” build phase happens so late in the build process that it’s after the last user-specified custom build phase. There’s no room in Xcode’s current design for fixing up the problematic entitlements before they are incorporated into the signed product. As far as I can tell the only clean workaround would be to redundantly re-sign the child app with a custom script, and corrected entitlements, after Xcode’s build process is completed.

I filed Radar #34628449, “Sandboxed project build with Xcode 9 cannot launch child process.”

Update: Colin Barrett pointed out on Twitter that the entitlement in question here, “”, may be required in order to attach to and debug a process. If true, then I think this is something that was handled in a different way in Xcode 8. I can confirm that my apps do not have the entitlement imposed on them by Xcode 8, yet I am able to attach to and debug them.

If Apple changed the debugger infrastructure in Xcode 9 so that the relationship between the debugger and target processes is more locked down, requiring a specific entitlement, then that’s probably a good thing. But if this change was made without thinking about the implications for the above-cited “strict two entitlement” rule for sandbox inheritance, then probably some flexibility needs to be applied to that rule.

Finally, as I noted above the entitlement is being applied to all my targets. What I didn’t clarify is that the entitlement is added even when Building and Archiving. A release build’s binaries are endowed with this additional entitlement, which may also bring additional security vulnerabilities to the app.

I would not ship a sandboxed Mac app that is built with Xcode 9, until we understand more about when Xcode applies this entitlement, and whether it can be prevented for Release builds at the very least.

Update 2: I’ve learned that Xcode’s “Export Archive” functionality causes the unwanted entitlement to be removed. Apparently the assumption is that everybody creates Xcode archives as part of their build and release process. I am sure this is true for most (all?) iOS deployments, but for Developer-ID signed apps on the Mac, there has traditionally been less of an incentive to do this. Got a properly signed Mac application? Zip it up, put it on a web server, and you’re done.

I’m not sure yet whether I’ll switch my build process to use archiving, or whether I’ll pull some other stunt to redo the code signing with corrected entitlements. In any case this has been quite an adventure today getting to the bottom of this. I updated my bug report with Apple to request that they provide some standard build flag that would prevent the problematic entitlement from being added from the start. In the mean time, I’ll explore one of the workarounds and get my builds back to fully functional!

JavaScript OSA Handler Invocation

When Apple added support to macOS to support JavaScript for Automation, they did so in a way that more or less allows folks who invoke AppleScripts to invoke JavaScript for Automation scripts as if they were exactly the same. An abstraction in Apple’s Open Script Architecture (OSA) makes it easy for script-running tools to theoretically handle any number of scripting languages without concern for the implementation details of those languages.

This mostly works, but I recently received a bug report that shed light on a problem with Apple’s implementation of JavaScript with respect to invoking a specific named handler. The OSA provides a mechanism for loading and running a specific handler, or function, within a script. My app FastScripts takes advantage of this to query a script about whether it would prefer to be invoked in another process or not. Unfortunately, when it comes to JavaScript, Apple’s implementation runs the whole script in addition to running just the specific, named handler.

If you’ve got Xcode handy, you can use this simple playground content to observe the problem:

import OSAKit

if let javaScriptLanguage = OSALanguage(forName: "JavaScript") {
   let scriptSource = "Application('Safari').activate();" +
         "function boo() { ObjC.import('Cocoa'); $.NSBeep(); }"
   let myScript = OSAScript(source: scriptSource, language: javaScriptLanguage)

  // Only the behavior of boo should be observed
  myScript.executeHandler(withName: "boo", arguments: [], error: nil)

// Give time for the beep to sound Date(timeIntervalSinceNow:5))

The named function “boo()” only invokes NSBeep, so when this playground is run, all that should happen is a beep should be emitted from the Mac. Instead, when it runs Safari becomes the active application. This is because in addition to running the “boo()” handler, it also runs the whole script at the top level.

A workaround to the bug is to wrap the top level functionality of a script in a “run()” handler, so where the scriptSource is declared above, instead use:

   let scriptSource = "function run() { Application('Safari').activate(); }" +
         "function boo() { ObjC.import('Cocoa'); $.NSBeep(); }"

I hope this helps the one other person on earth who cares about invoking JavaScript for Automation methods indvidually! (Radar #33962901, though I’m not holding my breath on this one!)

Xcode GitHub Integration

Apple’s beta release of Xcode 9 features impressive improvements to its source control features, including streamlined integration with GitHub. There’s even a fancy “Open in Xcode” button when you go to clone a project:

Screen capture of the GitHub interface for cloning a project

This integration is amazing. You just click the button, specify a save folder in Xcode, and boom! You’re off and …

Screen capture of build failure indicating a missing signing certificate

Oh, right. Code signing. The otherwise stellar GitHub integration in Xcode underscores a longstanding deficiency in how it manages code signing identities for multi-team, collaborative projects. Precisely the kinds of projects you’re liable to find on GitHub.

The problem could be solved, or at least diminished greatly, by providing some mechanism for declaring that a project should be code signed “with the user’s own default developer team.” The default branch of any open source project targeting Apple platforms, would specify the DEVELOPMENT_TEAM as something like:


Xcode would provide a user-level setting for “Default Development Team”, and in the absence of any overriding setting, that team would be used whenever a project was configured as above.

I wrote about this problem once before, but with all the work being put into streamlining the experience of cloning from and pushing to GitHub, now is an ideal time for Apple to embrace a fix. Radar #32614751.

Another issue that stops short the cloning, and immediate building and running, of open source projects, is the need to fulfill external dependencies. In some cases this might require manually downloading and installing libraries, or cloning projects, but in the vast majority of cases the dependencies will be specified using built-in Git submodule support, or a popular package manager. In each of these cases, it should be trivial for Xcode to detect that the project it has just cloned also has dependencies:

  • Git submodules: there is a .gitmodules directory.
  • Carthage: there is a Cartfile file.
  • CocoaPods: there is a Podfile file.
  • Swift Package Manager: there is a Swift.package file.

If Xcode sees evidence of any of these techniques at play, it could do the favor of checking them out immediately after cloning the project. Radar #32615265.

The GitHub integration coming in Xcode 9 provides a nearly effortless capability for cloning, building, and running open source projects that target Apple platforms. Ideally it would also go the extra mile and provide for variable, dynamic development teams, as well as conduct a rudimentary check for dependencies that must be checked out before commencing work on the project.

Window Tabbing Pox

macOS Sierra introduces a new system-wide window tabbing feature, which by default enables tabs within the windows of most document-based apps. Apple’s own TextEdit is a canonical example: open the app and select View -> Show Tab Bar to see how it looks.

Unfortunately, the default tabbing behaviors doesn’t make sense in all apps, even if they are document-based. I’ve had to disable the functionality in both MarsEdit and Black Ink, at least for the time being. Doing so is easy. Just add the following line somewhere early in the lifetime of your app:

NSWindow.allowsAutomaticWindowTabbing = NO;

This class property on NSWindow shuts the whole window tabbing system out of your app, so you don’t have to fuss with how to disable it on a window-by-window basis. Handy!

Unfortunately, setting that property to NO doesn’t do anything about windows that may already have been created, and which have their tab bar visible. I added the line to my app delegate’s applicationDidFinishLaunching: method, assuming that would take care of everything. After all, any documents will be instantiated later in the app’s lifetime, right? Right?

Wrong. Not with window restoration, at least, which causes a freeze-drying and restoration of open document windows when a user quits and relaunches the app. The window in this circumstance is actually created before applicationDidFinishLaunching. If it had its tab bar visible when you quit, it will have the tab bar visible when it’s restored, even if you’ve since disabled all window tabbing for the app.

What’s worse? Showing or hiding the tab bar on any window sets that choice as the default for all future windows in the app. So even new documents that are created by users, and which don’t have their tab bar visible because you’ve disabled it app-wide, will have a tab bar appended when they are restored at launch time, because “Show Tab Bar” was the last user action before disabling tabbing altogether.

The long and short of it? An app stuck in this situation will not have a View -> Show/Hide Tab Bar, and none of its windows will support tabbing, except for any document that is restored at launch time. Even new documents that are created without tab bars will have the tab bar imposed the next launch.

I filed Radar 28578742, suggesting that setting NSWindow.allowsAutomaticWindowTabbing=NO should also turn off window tabbing for any open windows that have it enabled.

If your app gets stuck in this predicament, one workaround is to move the NSWindow.allowsAutomaticWindowTabbing=NO line to an even earlier point in your app’s lifetime, such as in your app’s main.m or main.swift file.

Xcode 6 On Sierra

Xcode 6 and Xcode 7 are not supported by Apple on macOS Sierra, and should not be used for production work.

But what if you have a good reason for running one or the other? Maybe you want to compare a behavior in the latest Xcode 8 with an earlier version of the app. Instead of keeping a virtual machine around, or a second partition with an older OS release, it is liberating to be able to run and test against older versions of Xcode.

So far, it appears that Xcode 7 “mostly works” in spite of being unsupported by Apple. I’ve run into some launch-time crashes, but reopening the app tends to succeed.

Xcode 6 will flat out fail to launch, because one of its internal plugins depends on a private framework (Ubiquity.framework) that is no longer present on macOS Sierra. If you were willing to hack a copy of Xcode 6, however, you could get it running. You definitely shouldn’t do this, but if you’re curious how it could be done, here’s how:

  1. Always have a backup copy of any data that is important to you.
  2. Locate a copy of /System/Library/PrivateFrameworks/Ubiquity.framework from the previous OS X release.
  3. Copy the framework to within Xcode 6’s own Contents/Frameworks bundle subfolder:
    ditto /my/old/System/Library/PrivateFrameworks/Ubiquity.framework ./
  4. Navigate to the problematic Xcode plugin and modify its library lookup table so that it points to the app-bundled copy of Ubiquity.framework, instead of the non-existent system-installed copy.
    install_name_tool -change /System/Library/PrivateFrameworks/Ubiquity.framework/Versions/A/Ubiquity @rpath/Ubiquity.framework/Versions/A/Ubiquity ./iCloudSupport
  5. Now that you've modified Xcode, its code signature is invalid. You can repair it by signing it with your own credentials or with an ad hoc credential:
    codesign --deep -f -s - ./
  6. Did I mention you really shouldn't do this?

Apple has good reason to warn people off running older versions of Xcode, but if you absolutely need to get something running again, it's often possible.

Swift Maturity

Ted Kremenek of Apple announced on the Swift evolution announcements mailing list that the team will no longer accept source-breaking changes for Swift 3. That is, changes that would require developers’ own Swift code to change. He notes that this means many desirable features will not make the cut, and will have to be pushed to Swift 3.1 or beyond:

The challenge of course is reconciling these diametrically opposing goals: maintaining source stability while having the ability to incorporate more core (and important) language changes that are possibly source-breaking.

How will they balance this going forward? He hints that the team wants to support a mechanism whereby developers can specify a version of Swift as a parameter to the compiler. Your code builds against Swift 3.1? The Swift 4 compiler will be able to handle that:

Our goal is to allow app developers to combine a mix of Swift modules (e.g., SwiftPM packages), where each module is known to compile with a specific version of the language (module A works with Swift 3, module B works with Swift 3.1, etc.), then combine those modules into a single binary.

This is great news for developers, but only strengthens my argument that Swift needs a mechanism for SDK-conditional compilation. At this point, a developer who wishes to maintain source code that compiles against, say, iOS 9 and iOS 10, must conditionalize on the version of Swift:

#if swift(>=2.3)
	// iOS 10 only code
	// iOS 9 friendly code

When and if Ted Kremenek’s promise of a multiversioned Swift compiler comes to pass, it will presumably mean multiple versions of Swift can compile against the same SDK, so this fragile workaround will no longer … work.

Update: It occurs to me, multiple versions of Swift already do build against the same SDK. Currently we have Swift 2.3 and Swift 3 building against Apple’s latest beta SDKs. It’s the “>=” in the workaround that guarantees a suitable SDK match for now.