Category Archives: Xcode

Casting Objective-C Message Sends

Mike Ash shares interesting news that the latest Xcode SDKs include a change to the function prototype of Objective-C’s msgSend family of functions. Where objc_msgSend was previously defined in terms of the couple of parameters it usually takes, and with the return type that it sometimes has, it is now declared as taking no parameters and returning no value:

OBJC_EXPORT void
objc_msgSend(void /* id self, SEL op, ... */ )

In practial terms, this will have an impact if you are still using direct objc_msgSend calls anywhere in your code. For example, imagine you have a “transformer” class that is capable of performing a variety of text manipulations on strings. You might have some code that derives a “SEL” programmatically and then messages the transformer to perform the action. Here’s a contrived example:

SEL tSEL = @selector(uppercaseString:);
NSString* upString = objc_msgSend(transformer, tSEL, lowString);

While that would have worked previously (apart from some ARC warnings), on the latest SDKs you’ll get a compile-time error on the objc_msgSend call:

Too many arguments to function call, expected 0, have 3

Obviously, you need to pass the arguments or the invocation will be useless, but how do you do it? Mike’s post has the advice:

Because it still has a function type, you can still cast it to a function pointer of the appropriate type and invoke it that way. This will work correctly as long as you get the types right.

As long as you get the types right … so, how does one do that? Mike includes an example of inline-casting objc_msgSend, but if you need to do this more than once in your code, I think a more elegant way of casting objc_msgSend is by declaring a global variable as a function pointer with the desired types:

#import "objc/message.h"

NSString* (*PerformWithStringReturningString)(id, SEL, NSString*) = (NSString* (*)(id, SEL, NSString*)) objc_msgSend;

Now when you want to invoke “objc_msgSend” on an object that you know accepts and returns a string type, you can do so like this:

NSString* upString = PerformWithStringReturningString(transformer, tSEL, lowString);

No compiler warnings, ARC knows just what to do with all the types, and you have a very clear understanding of what objc_msgSend is expected to do with this particular invocation.

Notarization Provider IDs

With the release of macOS 10.15 fast-approaching, more and more Mac developers will be scurrying to ensure their apps are notarized. This is the process by which binary applications are submitted to Apple for cryptographic seal-of-approval indicating that the app meets minimum requirements for safety, and shows no obvious signs of being malware.

Apple offers substantial documentation about notarizing your apps. Many developers will find that Xcode automatically notarizes the app as part of the built-in process for archiving an app for release. For those of us with existing, automated command-line build & release processes, there is a separate guide just for us:

Customizing the Notarization Workflow

The steps for automating notarization involve running the “altool” command from Terminal. Everything in the guide linked above should work perfectly unless you’re a member of more than one development team. If you have more than one team associated with your Apple ID, the back-end at Apple doesn’t know which one it should notarize on behalf of. You’ll see an error message like this:

Error: Your Apple ID account is attached to other iTunes providers. You will need to specify which provider you intend to submit content to by using the -itc_provider command. Please contact us if you have questions or need help. (1627)

Here’s where things get fun: what the heck is your ITC provider ID? It’s not listed anywhere obvious on the Apple developer site or in Xcode, and can’t be obtained from the very tool that is asking for it. I came across a message from the ever-helpful Quinn in the Apple Developer Forums. It details a method for locating the provider ID by running a command-line tool, iTMSTransporter, from deep within Apple’s Application Loader app.

Application Loader has since been eliminated from Xcode 11, so if you’re running with modern tools, you’ll be hard pressed to find it. Fear not, the binary is preserved deep within the Xcode app bundle itself:

% xcrun -f iTMSTransporter
/Users/daniel/Applications/Xcode/Xcode.app/Contents/Developer/usr/bin/iTMSTransporter

All that said, here is a surefire list of steps for obtaining your ITC Provider ID, or as it’s described in the altool man page, your ASC Provider Shortcode.

  1. Create a new App-Specific Password from your Apple ID management page.
  2. From Terminal, invoke iTMSTransporter with the following options:
    xcrun iTMSTransporter -m provider -u <yourAppleID> -p <yourAppSpecificPassword>
    
  3. At your discretion, revoke the App-Specific Password you created for this process.

NOTE: These instructions apply if you are using Xcode 11. If you’re still using Xcode 10, you’ll need to dig up the iTMSTransporter binary from within Application Loader.app. Instead of “xcrun iTMSTransporter” above, it will be something like /path/to/Application Loader.app/Contents/itms/bin/iTMSTransporter.

If all goes well, you should see a list of your Apple development teams, including the Long Name and Short Name. The Short Name is what you need to pass whenever altool requires an ITC or ASC Provider ID.

Monolithic Workspace

I’ve been experimenting in Xcode with the idea of using one workspace that contains ALL of my projects. The idea is to give me the ability to quickly jump between building/testing different apps, and to make it easier to do global refactoring of common code that is shared among all my apps.

Screenshot of Xcode's source list area with a large number of project icons referencing various apps and libraries

The challenge here is rooted in Xcode’s inability to maintain more than one open reference to a project at a time. If you have a common library “CoreFunctions.framework” and several apps with “CoreFunctions.xcodeproj” embedded in them, then the first app you open in Xcode that references it “wins,” and all the subsequent apps end up with un-expandable proxy icons for the project reference.

The monolithic workspace is a bit unwieldy but great to not have to do the close and reopen dance every time I want to check whether a change to a common framework has an impact on another app.

The main nuisance I find in working in the workspace is navigating the massive number of projects and file hierarchies that may be expanded at any time. What I’d like to be able to do is to borrow a trick from OmniFocus, and “focus” on just one project in my workspace at a time. Apple already offers the ability to focus search on a subset of files. Just right-click on a project or folder in the source list, and “Find in Selected Groups”:

Contextual menu showing a menu item to 'Find in Selected Groups' title=

If I could “Focus on Selected Groups” then I imagine being able to work primarily within a project, say BlackInk.xcodeproj, while maintaining all the open references in the workspace for the benefits of global searching and streamlining switches between active schemes. This functionality could be paired with Xcode’s tabbed window support to effectively provide separate workspaces that work in conjunction with one another. Radar #45908260.

Let it Rip

In the latest Mojave public beta, I noticed a foreboding warning in the console when I build and run FastScripts, my macOS scripting utility:

FastScripts [...] is calling TIS/TSM in non-main thread environment, ERROR : This is NOT allowed. Please call TIS/TSM in main thread!!!

Ruh-roh, that doesn’t sound good. Particularly with the emphasis of three, count them three, exclamation points! I better figure out what’s going on here. But how?

Sometimes when Apple adds a log message like this, they are kind enough to offer advice about what to do to alleviate the problem. Sometimes the advice implores that we stop using a deprecated method, or in a scenario like this, offers a symbolic breakpoint we might set to zero in on exactly where the offending code lies. For example, a quick survey of my open Console app reveals:

default	11:54:18.482226 -0400	com.apple.WebKit.WebContent	Set a breakpoint at SLSLogBreak to catch errors/faults as they are logged.

This particular warning doesn’t seem to apply to my app, but if it did, I would have something good to go on if I wanted to learn more. With the TIS/TSM warning, however, I have no idea where to go. Do I even use TIS/TSM? What is TSM?

I’ve worked on Apple platforms for long enough to know that TSM stands for Text Services Manager. However, I have also worked on these platforms long enough to forget whether I’ve actually used, or am still using, such a framework in my apps! When these kinds of warnings appear in the console, as many times as not they reflect imperfections in Apple’s own framework code. Is it something Apple’s doing, or something I’m doing, that’s triggering this message?

Ideally we could set a breakpoint on the very line of code that causes this console message to be printed. This can be surprisingly difficult though. There have always been a variety of logging mechanisms. Should you set the breakpoint on NSLog, os_log, printf, fprintf, or write? I could probably figure out a comprehensive method for catching anything that might write to the console, but am I even sure this console method is being generated in my app’s main process? There are a lot of variables here. (Hah! In this particular case, I ended up digging deeper and discovering it calls “CFLog”).

This is a scenario where combining lldb’s powerful “regular expression breakpoints” and “breakpoint commands” can help a great deal. Early in my app’s launch, before the warning messages are logged, I break in lldb and add a breakpoint:

(lldb) break set -r TIS|TSM.*

I’m banking on the likelihood that whatever function is leading to this warning contains the pertinent framework prefixes. It turns out to be a good bet:

Breakpoint 5: 634 locations.

I hit continue and let my app continue launching. Here’s the problem, though: those 634 breakpoint locations include quite a few that are getting hit on a regular basis, and for several consecutive breaks, none of them is triggering the warning message I’m concerned about. This is a situation where I prefer to “let it rip” and sort out the details later:

(lldb) break command add 5
Enter your debugger command(s).  Type 'DONE' to end.
> bt
> c
> DONE
(lldb) c
Process 16022 resuming

What this does is add a series of commands that will be run automatically by lldb whenever breakpoint 5 (the one I just set) is hit. This applies to any of the 634 locations that are associated with the regular expression I provided. When the breakpoint is hit, it will first invoke the “bt” command to print a backtrace of all the calls leading up to this call, and then it will invoke the “continue” command to keep running the app. After the app has run for a bit, I search the debugger console for “!!!” which I remembered from the original warning. Locating it, I simply scroll up to see the backtrace command that had most recently been invoked:

  thread #7, stop reason = breakpoint 5.568
    frame #0: 0x00007fff2cd520fd HIToolbox`TSMGetInputSourceProperty
    frame #1: 0x00000001003faef2 RSFoundation`-[RSKeyboardStatus update](self=0x00006000002b8c00, _cmd="update") at RSKeyboardStatus.m:56
    [...]

Command #2 'c' continued the target.
2018-08-14 12:15:40.326538-0400 FastScripts[16022:624168] pid(16022)/euid(501) is calling TIS/TSM in non-main thread environment, ERROR : This is NOT allowed. Please call TIS/TSM in main thread!!! 

Sure enough, that’s my code. I’m calling TSM framework functions to handle key translation for FastScripts’s keyboard shortcut functionality, and I’m doing it (gasp!) from thread #7, which is certainly not the main thread. I oughta be ashamed…

But I’m proud, because I tracked down the root of the problem pretty efficiently using lldb’s fantastic breakpoint commands. Next time you’re at a loss for how or where something could possibly be happening, consider the possibility of setting a broad, regular expression based breakpoint, and a series of commands to help clarify what’s happening when those breakpoints are hit. Then? Let it rip!

Completely Useful

Particularly as a developer coming from an Objective C background, it’s common to head into an override implementation in a subclass thinking of a property as a function. For this reason, I find myself commonly starting to implement a property override by typing something like “override func canBecome” when I want to override UIView’s “canBecomeFirstResponder”. A completion pops up like this:

Screenshot of Xcode offering a code completion with non-pertinent options.

Instead of the expected method, Xcode has twisted itself into knots to contrive that letters from the whole prototype for “addObserver” can be used to spell out “canBecome”. Not particularly useful.

It always takes me a few seconds, or longer, to realize that I haven’t misremembered the existence of a method or property that I want to override, I’ve simply disregarded whether it’s identified in Swift as a “var” or a “func”. One simple change to “override var canBecome” does the trick:

Screenshot of Xcode offering a useful code completion popup list.

In my not so very humble at all opinion, Xcode should go the extra mile here and look for matches in the “var” realm when you’ve type “func”, and vice-versa. If it finds something that perfectly matches everything you’ve typed except whether it’s a func or a var, then it should offer the completion and fix the mistyped designation when you accept it. I’ve filed Radar #42660012 requesting this enhancement.

Update: Several folks have suggested a good workaround: simply get in the habit of omitting the decorative terms, such as “override”, “func”, and “var”. It turns out if you leave out the narrowing term, Xcode does find the pertinent matches, and also inserts the required decoration upon inserting one.

My friend Chris Liscio pointed out that changing the behavior as I recommend might be a questionable move, because it defies a kind of rule for type-completion. In general, whatever the user has already typed should be considered what the user knows they want, and completion should only offer pertinent matches. It’s a compelling argument but I think that in cases like this the computer actually knows more about what I really want than I do.

Getting a CFNumber’s Value in Swift

Recently, as a consequence of working with the CGImageSource API, I found myself in a situation where I had hold of a CFNumber and wanted to get its value, as a CGFloat, in Swift.

CFNumber wraps numeric values in such a way that, to get the value out, you have to specify both the desired type, and provide a pointer to the memory of the variable that will hold the value. This kind of direct memory manipulation is not particularly suited to Swift’s priorities for type safety and memory protection. Here’s the API I’d need to use in Swift:

func CFNumberGetValue(_ number: CFNumber!, 
                    _ theType: CFNumberType, 
                    _ valuePtr: UnsafeMutableRawPointer!) -> Bool

The first two parameters are straightforward, but whenever I see types like “UnsafeMutableRawPointer” in Swift, my brain melts down a little. I have never really sat down to truly understand the nuanced differences between these types, so I usually just try something and hope it works. Here I am hoping for a gift from Swift’s implicit bridging:

// myCFNumber is 30.5
var myFloat: CGFloat = 0
CFNumberGetValue(myCFNumber, .floatType, &myFloat)
print(myFloat) // "5.46688490824244e-315\n"

Welp. That didn’t work. Let’s see if we can refresh our memory about UnsafeMutableRawPointer. In the section titled “Raw, Unitialized Memory” or I read:

You can use methods like initializeMemory(as:from:) and moveInitializeMemory(as:from:count:) to bind raw memory to a type and initialize it with a value or series of values.

Oh jeez, am I really going to have to manually create an UnsafeMutableRawPointer? I’ll try anything:

var myFloat: CGFloat = 0
var myFloatPointer = UnsafeMutableRawPointer(mutating: &myFloat)
CFNumberGetValue(myCFNumber, .floatType, myFloatPointer)
print(myFloat) // "5.46688490824244e-315\n"

Alas, same problem. Surely somebody has figured this out? I try Googling for “CFNumberGetValue Swift GitHub” and find a promising result from an authoritative source. The Swift standard library itself!

var value: Float = 0
CFNumberGetValue(_cfObject, kCFNumberFloatType, &value)

Aha! Practically the same thing I was doing, except for one nuanced detail: the var value is declared as a Float instead of a CGFloat. But wait a minute, what file is this implementation in? NSNumber.swift? Oh, right. NSNumber and CFNumber are toll-free bridged, and Swift’s standard library fulfills that promise too:

let myFloat = (myCFNumber as NSNumber).floatValue
print(myFloat) // 30.5

In fact, Swift’s Float type is even cozier with CFNumber than I expected. What started as a confused mission to make use of CFNumberGetValue and its unsafe pointer argument culminated in a bit of sample code from GitHub that ultimately led me to the understanding that the way to get a CFNumber’s value in Swift is … simply to ask for it:

let myFloat = Float(myCFNumber)
print(myFloat) // 30.5

Optional Emptiness

Objective-C developers are comfortable with many idioms that fall out of the safety of messaging nil. For example, consider a chunk of Objective-C code that tests the “emptiness” of a UITextField string:

if (myTextField.text.length == 0) {
    // Do something
}

If myTextField.text is nil, what happens? In Objective-C, a message sent to nil will return nil, or zero, depending on the return type of the message. In this case “length” returns an integer, which happens to be zero when text is an empty string, and zero when text is nil. So this code block perfectly expresses “if the text is empty, do something.”

Adapting this code to Swift, you immediately run up against the language’s strict handling of optionals. Because myTextField.text might be nil, it has to be unwrapped before the length method can be called. This leads to less terse code such as:

if myTextField.text?.isEmpty != false {
    // Do something
}

This works! But it’s harder to read, and harder to reason. Similarly to the way the Objective-C version requires deep understanding of that language’s nil-messaging behavior, the Swift version requires deep understanding of optional chaining and comparison of optional and non-optional values. Here’s another example:

if (myTextField.text ?? "").isEmpty {
    // Do something
}

This is much easier to understand: use the non-nil String from myTextField, or else a constant string that is guaranteed to return true for isEmpty. It’s still more cumbersome than the original Objective-C, though.

In my own Swift adventures, I’ve addressed this using Swift’s powerful extension mechanism. It turns out that in Swift, any type that conforms to the “Collection” protocol implements an “isEmpty” method. String is one of these types. So with a small extension, we can add the “isEmpty” method not only to String? but to all optionals that wrap a collection:

extension Optional where Wrapped: Collection {
	public var isEmpty: Bool {
		switch(self) {
		case .none:
			return true
		case .some(let concreteSelf):
			return concreteSelf.isEmpty
		}
	}
}

With this extension in place, our test becomes:

if myTextField.text.isEmpty {
    // Do something
}

Which is both highly readable, behaves correctly when “text” is nil, and doesn’t require any deep language understanding to comprehend.

Thanks to Hwee-Boon Yar for the Objective-C scenario that motivated this post, and to Michel Fortin for putting forward the Swift equivalents cited above. This question came up in the Core Intuition Slack, where interesting discussions like this often take place. Join us!

Swift Integration Traps

In the nearly four years since Swift was announced at WWDC 2014, Mac and iOS developers have embraced the language with decreasing reluctance. As language features evolve, syntax stabilizes, and tooling improves, it’s easier than ever to leap into full-fledged Swift development.

Several months ago, I myself made this leap. Although the vast majority of my Mac source base consists of Objective-C files, I have enjoyed adding new source files in Swift, and even converting key files to Swift either as an exercise, or when I think I will gain specific advantages.

One remaining challenge in Swift is the lack of ABI stability. In layperson’s terms: the lack of ABI stability prevents compiled Swift code from one version of the Swift compiler and runtime from linking with and running in tandem with Swift code compiled for another version.

For most developers, this limitation simply means that the entire Swift standard library, along with glue libraries for linking to system frameworks, needs to be bundled with the application that is built with Swift. Although it’s a nuisance that several megabytes of libraries must be added to every single Swift app, in the big scheme of things, it’s not a big deal.

A worse consequence is the number of pitfalls that ABI instability present, that are difficult to understand intuitively, and in many cases impossible, or at least dangerous, to work around. These pitfalls lie mainly in areas where developer code is executed on behalf of a system service, in a system process. In this context, it is not possible for developers to ensure that the required version of Swift libraries will be available to support their code. Game over.

On the Mac, system integration plugins are a typical scenario for this problem. While iOS has evolved with a strong architecture for running developer code in standalone, sandboxed processes, on the Mac there are still many plugins that run in a shared system process alongside code from other developers. These plugins run the gamut from arcane, rarely used functionality, to very common, user-facing features where a plugin is effectively required in order to satisfy the platform behaviors prescribed by Apple and expected by end-users.

One example on the more arcane, or at least inessential, end of the spectrum, is the Screen Saver plugin interface. Create a new project in Xcode, and choose the “Screen Saver Plugin” template as your starting point. Notice how unlike most templates, Xcode doesn’t even offer a choice of language. Your source files will be Objective-C. At least they’re giving you a hint here.

On the more mainstream end of the spectrum are plugins such as System Preferences panels and QuickLook Plugins. Depending on the type of app you are developing, it may be essential, or at least very well-advised to implement one of these types of plugins. So what do you do if you have an existing Objective-C app that you want to port to Swift, or you are writing a Swift app from scratch, and need to support one of these plugin formats? In the case of System Preferences panels at least, you have a couple practical options:

  1. Implement the plugin code, and all supporting code in Objective-C.
  2. Move the functionality out of System Preferences and into the host app.

Each of these could be somewhat reasonable approaches for a System Preferences plugin. The content of these plugins is often fairly straightforward, standard UI, and the goal is usually to collect configuration data to convey to the host application. It’s also not unreasonable, and may even be preferable to move such configuration code out of System Preferences and into a native panel inside the host app.

QuickLook Plugins are another beast. Because the goal of a QuickLook Plugin is usually to convey a visual depiction of a native document type, it’s exceedingly common to take advantage of the very classes that present the document natively in the host app. Let’s say you’ve written an app in Swift, FancyGraphMaker. Apple encourages you to implement a QuickLook Plugin so that users will be able preview the appearance of your fancy graphs, both in the dedicated QuickLook interface, and by way of more unique looking icons in the Finder.

But once you’ve written the code to draw those fancy graphs in Swift, you’re locked out of using that code from a QuickLook Plugin. Worse? Finishing touches such as supporting Quick Look are liable to come later in the development of an app, so you’ve probably gone through the decision-making process of writing your app in Swift, before realizing that the decision effectively cuts you off from a key system feature. That’s a Swift Integration Trap.

Although the workarounds are not as straight-forward in this scenario as they are for a System Preferences pane, it is probably still technically possible to leverage Swift code in the implementation of a QuickLook Plugin. I have not tested this, but I imagine such a plugin could spawn an XPC process that is itself implemented in Swift and executes the bulk of the preview-generation work on behalf of the system-encumbered plugin code. The XPC process would be free to link to whatever bundled Swift libraries it requires, generate the desired preview data, and message it back to the host process. At least, I think that would work.

But I shouldn’t have to think that hard to get this to work, nor should any other developer. The problem with these Swift Integration Traps is twofold:

  1. If you don’t know about them, you end up stuck, potentially regretting the decision to move to Swift.
  2. If you do know about them, you might put off adopting Swift completely, or at least put off converting classes that are pertinent to QuickLook preview generation.

Each of these consequences is bad for developers, for users, and for Apple. Developers face a trickier decision process about whether to move to Swift, users face potential integration shortcomings for Swift-based apps, and Apple suffers either reduced adoption of Swift, reduced integration with system services, or both.

I filed Radar #38792518 requesting that QuickLook Plugins be supported by the App Extension model. Essentially, this would formalize the process of putting the generation code in a separate XPC process, as I speculated above would work around the problem. The App Extension system is designed to support, and in fact requires this approach. The faster Apple moves QuickLook Plugins, and other shared-process plugins to the App Extension model, the fast developers can embrace Swift with full knowledge that their efforts to integrate with the system will not be stymied.

Update: Thanks to a hint from Chris Liscio, I have learned that Apple has in fact made some progress on the QuickLook front, but it won’t help the vast majority of cases in which a QuickLook Plugin is used to provide previews for custom file types. It took me a while to hunt this down because it not very clearly documented, and Google searches do not lead to information about it.

At WWDC 2017, Apple announced support for a new QuickLook Preview Extension. It escaped my notice even while ardently searching for evidence of such a beast, because the news was shared in the What’s New in Core Spotlight session. Making matters worse, the term “QuickLook” does not appear once in the session transcript, although it turns out that “Quick Look” appears many times:

Core Spotlight is also coming to macOS and just like on iOS you can customize your preview. On macOS a preview is shown when you select a search result in the Spotlight window. Here you really do want to implement a Quick Look preview extension for your Core Spotlight item because Spotlight on macOS does not have a default preview.

Ooh, this sounds exciting! I’ve wondered over the years why such similar plugins, Spotlight importers, and QuickLook generators, shouldn’t be unified. Although the WWDC presentation emphasizes substantial parity in behavior for QuickLook Previews between iOS and macOS, there is a major gotcha:

Core Spotlight is great for databases and shoeboxes where your app has full control over the contents.
It’s not for items that the user monitors in the finder, for that the classic Spotlight API still exists and still works great.

I beg to differ with that “still works great” assessment, at least in the context of this post. Mac developers who want to integrate with QuickLook must still use a shared-process plugin. It’s still a Swift Integration Trap.

IDEBundleInjection Signing Failure

When a unit test bundle is built to be dynamically injected into a host app, Xcode performs a little dance at build time, in which it adds its own IDEBundleInjection.framework to the bundle, then re-signs it with the developer’s code signing identity.

Normally this all goes off without a hitch, but today when I went to build and test such a bundle, I was met with a rude code signing failure:

IDEBundleInjection.framework: unsealed contents present in the root directory of an embedded framework

I took all the usual steps when facing an obtuse error: clean the build directory, quit and restart Xcode, etc. Nothing fixed it, so I thought perhaps it was an issue with the 9.3 beta Xcode I was running. Nope. Same problem with 9.2. Finally, I made my own copy of the framework in question, and ran “codesign” against it myself from the Terminal. Same error!

This framework, stored within Xcode itself, has become unsignable. Running “codesign -v” against the framework in place also confirms that the code signing seal has been broken. What happened to my Xcode?

It occurred to me that I recently migrated from one Mac to another, and copied my Xcode when I did. I tried to use the Apple-standard migration assistant, but it failed, so I ended up using Finder, or ditto from the Terminal, to copy everything over. Maybe something was messed up in the transition?

The codesign utility is useful for letting me know that something is wrong, but doesn’t actually do me the favor of telling me what it is! Luckily, I have a backup of my whole disk and the original Xcode on that volume appear to have properly signed internal frameworks. Running a diff on IDEBundleInjection.framework between the two copies, I do see some reported distinctions. Where “.” is the current, misbehaving framework:

Only in .: .BC.D_QdfhyO
Only in .: .BC.D_mgLUu2
Only in ./Versions: .BC.D_gSVCxT

These appear to be redundant cruft correlating to the expected internal version links. For every link like:

IDEBundleInjection -> Versions/Current/IDEBundleInjection

I have one of these unexpected garbage links. The presence of these links are, of course, detected by codesign, and it throws everything off.

I don’t know why these mysterious gremlin files showed up on my Mac, but whatever the cause, there’s an easy solution. I’m taking a leap of faith that I don’t actually want any of these files:

cd /Applications/Xcode.app
find . -name ".BC.*" -delete

And now I can get back to unit testing my app.

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?

Nothing.

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:

  • “com.apple.XCTPerformanceMetric_WallClockTime”
  • “com.apple.XCTPerformanceMetric_UserTime”
  • “com.apple.XCTPerformanceMetric_RunTime”
  • “com.apple.XCTPerformanceMetric_SystemTime”

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

  • “com.apple.XCTPerformanceMetric_TransientVMAllocationsKilobytes”
  • “com.apple.XCTPerformanceMetric_TemporaryHeapAllocationsKilobytes”
  • “com.apple.XCTPerformanceMetric_HighWaterMarkForVMAllocations”
  • “com.apple.XCTPerformanceMetric_TotalHeapAllocationsKilobytes”
  • “com.apple.XCTPerformanceMetric_PersistentVMAllocations”
  • “com.apple.XCTPerformanceMetric_PersistentHeapAllocations”
  • “com.apple.XCTPerformanceMetric_TransientHeapAllocationsKilobytes”
  • “com.apple.XCTPerformanceMetric_PersistentHeapAllocationsNodes”
  • “com.apple.XCTPerformanceMetric_HighWaterMarkForHeapAllocations”
  • “com.apple.XCTPerformanceMetric_TransientHeapAllocationsNodes”

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, "com.apple.XCTPerformanceMetric_TransientHeapAllocationsKilobytes", "com.apple.XCTPerformanceMetric_PersistentVMAllocations", "com.apple.XCTPerformanceMetric_UserTime"]
}

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!

Enjoy.