Category Archives: OS X

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 ./Xcode.app/Contents/Frameworks/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.
    cd Xcode.app/Contents/PlugIns/iCloudSupport.ideplugin/Contents/MacOS
    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 - ./Xcode.app
    
  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.

Pasteboard Priority

A weird bug cropped up in MarsEdit, in which a URL copied and pasted from Safari, for example, was pasting into the plain text editor as the text from the link instead of the link itself. Daring Fireball’s star glyph permalinks to entries presented a most dramatic example. Right-clicking a star glyph and copying the link to paste into MarsEdit was supposed to yield:

Image of pasted link shown as expected with full text content of URL

But instead gave:

Image of pasted URL showing the text of the link instead of the URL content

How strange. What could have possibly changed something so fundamental as the manner in which a pasted link is processed by my text editor? I leaned on Mercurial’s “bisect” command which led me to the specific source code commit where the behavior had changed, in my text view’s helper method for building a list of acceptable paste types. My color emphasis is on the changed part:

-	return [[NSArray arrayWithObject:NSFilenamesPboardType] arrayByAddingObjectsFromArray:[NSImage imageFileTypes]];
+	return [[NSArray arrayWithObject:NSFilenamesPboardType] arrayByAddingObjectsFromArray:[NSImage imageTypes]];

That’s it? One little tweak to the construction of a list of image types affects the behavior of pasting a URL copied from Safari? Programming is hard.

I had made the change above because imageFileTypes is deprecated. The deprecation warning specifically says: “use imageTypes instead.” Okay. Functionally, everything related to the image types should work the same. Instead of a list of file extensions from -imageFileTypes, I’m now getting a list of UTIs. I scrutinized the lists a bit to satisfy myself that all of the major image types were present in the new list, and I trust that Apple had covered the bases when they made this migration themselves.

It turns out the change above, the one word diff that causes everything to work either as expected or otherwise, is fine. It’s outside of this method where the real problem lies: in my override of NSTextView’s -readablePasteboardTypes method. In it, I endeavor to combine my own list of pasteable types with NSTextView’s own list. To do this, I create a mutable set to combine -[super readablePasteboardTypes] and my own list, and then return an array of the result. The idea is to avoid listing any items redundantly from the built in list and my own:

- (NSArray*) readablePasteboardTypes
{
	NSMutableSet* allReadableTypes = [NSMutableSet setWithArray:[super readablePasteboardTypes]];
	[allReadableTypes addObjectsFromArray:[self acceptableDragTypes]];
	return [allReadableTypes allObjects];
}

Ah, my spidey sense is finally starting to tingle. While it’s not mentioned in the NSTextView reference documentation, the NSTextView.h header file includes comments about this method that are pertinent here:

Returns an array of types that could be read currently in order of preference.  Subclassers should take care to consider the "preferred" part of the semantics of this method.

Ah, so order matters. Of course. And what does the -[NSSet allObjects] say about order?

The order of the objects in the array is undefined.

So all this time, I’ve been playing fast and loose with NSSet, lucking out with the coincidence that types I prefer would show up higher in the list than types I don’t prefer. It turns out that “public.url” is among the types included in NSTextView’s own, built-in readablePasteboardTypes method implementation, but previous to this change, it always showed up lower in resulting list than NSStringPboardType. Thus, when faced with an opportunity to paste a URL from Safari, rich with information including the original text from the link, MarsEdit always favored the plain string representation.

Changing from -[NSImage imageFileTypes] to -[NSImage imageTypes] effectively changed the roll of the dice, causing the resulting array from NSSet, documented as being “undefined” in its order, to place the URL type above the string type in the list. Thus it tries to paste as a rich URL with text linking to a URL, but since my plain text HTML editor doesn’t support rich text, all you see is the star.

The fix will be to arrange that my resulting array from readablePasteboardTypes does impose some predictable prioritization. Probably by taking the code that I have now and, after generating the list of all unique types, carefully moving a few types to the top of the list in the order that I’d prefer.

Principally Unclassy

I had a real head-scratcher of a bug with MarsEdit, manifesting as a subtle failure of specific AppleScript commands to work properly in the release builds of the app. It seemed as though AppleScript were unable to reckon any properties of my app stemming directly from the application object itself.

I was so perplexed that I found myself digging around inside AppleScript’s own internal handling of the command. Setting a breakpoint on -[NSScriptCommand executeCommand], I could trace the evaluation of the request from AppleScript, watching as it ultimately failed to handle the command and returned an error.

It made sense to discover that, in the course of determining how to handle the command, it would consult the application’s “top level object.” That is, the application object itself. I witnessed that AppleScript internally determines the object by calling something like this:

(lldb) po [[NSScriptExecutionContext sharedScriptExecutionContext] topLevelObject]
<NSApplication: 0x618000160600>

Well, that all looks pretty ordinary. Nothing to be alarmed by, right? Luckily, it jumped out at me as all wrong, even though it’s the subtlest of things. The instance returned above is of class NSApplication, which would normally be fine, except that I’ve subclassed NSApplication in my app. It should be of class MEApplication.

Apple doesn’t encourage subclassing NSApplication, but it’s well-documented and appropriate in some circumstances. I happen to implement some of MarsEdit’s high level scripting support in the NSApplication subclass.

I double-checked the target’s Info.plist file. Sure enough the value for NSPrincipalClass is “MEApplication”, so why am I getting an NSApplication instance instead? And why did this suddenly start happening in recent beta test releases of the app?

The answer is that I added an innocuous looking call to -[NSApplication sharedApplication] in MarsEdit’s main.m, before the call to NSApplicationMain. And this code path doesn’t get reached on Debug builds, only on Release ones. Sigh.

It’s in NSApplicationMain that the documented behavior occurs of looking up NSPrincipalClass from the Info.plist, and using that value to call -[WhateverClass sharedApplication]. By calling -[NSApplication sharedApplication] before that, I preemptively force the shared application instance to be of class NSApplication.

So remember, kids: don’t subclass NSApplication. But if you do, then don’t reference -sharedApplication before NSApplicationMain. And if you simply must, then make darned sure you explicitly target your custom subclass by name. For you iOS developers, this wisdom applies to UIApplication, as well!

Nasty. Yeah.

NSDebugScrolling

I’m working on some heavy NSTextView, NSScrollView, NSClipView type stuff in MarsEdit. This stuff is fraught with peril because of the intricate contract between the three classes to get everything in a text view, including its margins, scrolling offset, scroll bars, etc., all working and looking just right.

When faced with a problem I can’t solve by reading the documentation or Googling, I often find myself digging in at times, scratching my head, to Apple’s internal AppKit methods, to try to determine what I’m doing wrong. Or, just to learn with some certainty whether a specific method really does what I think the documentation says it does. Yeah, I’m weird like this.

I was cruising through -[NSClipView scrollToPoint:] today and I came across an enticing little test (actually in the internal _immediateScrollToPoint: support method):

0x7fff82d1e246 <+246>:  callq  0x7fff82d20562            ; _NSDebugScrolling

0x7fff82d1e24b <+251>:  testb  %al, %al

0x7fff82d1e24d <+253>:  je     0x7fff82d20130            ; <+8160>

0x7fff82d1e253 <+259>:  movq   -0x468(%rbp), %rdi

0x7fff82d1e25a <+266>:  callq  0x7fff8361635e            ; symbol stub for: NSStringFromSelector

0x7fff82d1e25f <+271>:  movq   %rax, %rcx

0x7fff82d1e262 <+274>:  xorl   %ebx, %ebx

0x7fff82d1e264 <+276>:  leaq   -0x118d54fb(%rip), %rdi   ; @“Exiting %@ scrollHoriz == scrollVert == 0”

0x7fff82d1e26b <+283>:  xorl   %eax, %eax

0x7fff82d1e26d <+285>:  movq   %rcx, %rsi

0x7fff82d1e270 <+288>:  callq  0x7fff83616274            ; symbol stub for: NSLog

 

Hey, _NSDebugScrolling? That sounds like something I could use right about now. It looks like AppKit is prepared to spit out some number of logging messages to benefit debugging this stuff, under some circumstances. So how do I get in on the party? Let’s step into _NSDebugScrolling:

AppKit`_NSDebugScrolling:

0x7fff82d20562 <+0>:   pushq  %rbp

0x7fff82d20563 <+1>:   movq   %rsp, %rbp

0x7fff82d20566 <+4>:   pushq  %r14

0x7fff82d20568 <+6>:   pushq  %rbx

0x7fff82d20569 <+7>:   movq   -0x11677e80(%rip), %rax   ; _NSDebugScrolling.cachedValue

0x7fff82d20570 <+14>:  cmpq   $-0x2, %rax

0x7fff82d20574 <+18>:  jne    0x7fff82d20615            ; <+179>

0x7fff82d2057a <+24>:  movq   -0x116a7ad9(%rip), %rdi   ; (void *)0x00007fff751a9b78: NSUserDefaults

0x7fff82d20581 <+31>:  movq   -0x116d5df8(%rip), %rsi   ; “standardUserDefaults”

0x7fff82d20588 <+38>:  movq   -0x1192263f(%rip), %rbx   ; (void *)0x00007fff882ed4c0: objc_msgSend

0x7fff82d2058f <+45>:  callq  *%rbx

0x7fff82d20591 <+47>:  movq   -0x116d5fa0(%rip), %rsi   ; “objectForKey:”

0x7fff82d20598 <+54>:  leaq   -0x118ab0cf(%rip), %rdx   ; @“NSDebugScrolling”

0x7fff82d2059f <+61>:  movq   %rax, %rdi

0x7fff82d205a2 <+64>:  callq  *%rbx

 

Aha! So all i have to do is set NSDebugScrolling to YES in my app’s preferences, and re-launch to get the benefit of this surely amazing mechanism. Open the Scheme Editor for the active scheme, and add the user defaults key to the arguments passed on launch:

Screenshot 3 29 16 3 50 PM

You can see a few other options in there that I sometimes run with. But unlike those, NSDebugScrolling appears to be undocumented. Googling for it yields only one result, where it’s mentioned offhand in a Macworld user forum as something “you could try.”

I re-launched my app, excited to see the plethora of debugging information that would stream across my console, undoubtedly providing the clues to solve whatever vexing little problem led me to stepping through AppKit assembly code in the first place. The results after running and scrolling the content in my app?

Exiting _immediateScrollToPoint: without attempting scroll copy ([self _isPixelAlignedInWindow]=1)

I was a little underwhelmed. To be fair, that might be interesting, if I had any idea what it meant. Given that I’m on a Retina-based Mac, it might indicate that a scrollToPoint: was attempted that would have amounted to a no-op because it was only scrolling, say, one pixel, on a display where scrolling must move by two pixels or more in order to be visible. I’m hoping it’s nothing to worry about.

But what else can I epect to be notified about by this flag? Judging from the assembly language at the top of this post, the way Apple imposes these messages in their code seems to be based on a compile-time macro that expands to always call that internal _NSDebugScrolling method, and then NSLog if it returns true. Based on the assumption that they use the same or similar macro everywhere these debugging logs are injected, I can resort to binary analysis from the Terminal:

cd /System/Library/Frameworks/AppKit.framework
otool -tvV AppKit | grep -C 20 _NSDebugScrolling

This dumps the disssembly of the AppKit framework binary, greps for _NSDebugScrolling, and asks that 20 lines of context before and after every match be provided. This gives me a pretty concise little summary of all the calls to _NSDebugScrolling in AppKit. It’s pretty darned concise. In all there are only 7 calls to _NSDebugScrolling, and given the context, you can see the types of NSLog strings would be printed in each case. None of it seems particularly suitable to the type of debugging I’m doing at the moment. It’s more like plumbing feedback from within the framework that would probably mainly be interesting from an internal implementor’s point of view. Which probably explain why this debugging key is not publicized, and is only available to folks who go sticking their nose in assembly code where it doesn’t belong.

Constraint Activation

I got started with Auto Layout a few years ago, and on the whole I’m very happy with the framework. It can be exceedingly frustrating at times, especially when some nuanced constraint priority or other is imposing a layout that just doesn’t make sense. But I measure its value by the degree to which I shudder in imagining going back to the old springs and struts approach.

Although some interfaces work perfectly with a fixed set of constraints, other interfaces require dynamic manipulation at runtime in order to achieve the desired result. For example, if a change in a preferences panel brings in some new element to the UI, it might make sense to adjust constraints at runtime to accommodate it.

Prior to OS X 10.10 and iOS 8.0, this could be achieved in a general case by removing and adding constraints as needed to the view in question:

  1. Remove constraints and save them somewhere, e.g. in an array, for later.
  2. Add or remove elements to the view.
  3. Add constraints, e.g. by fetching them from a saved array.

It is important to remove constraints and save them before removing an affected element, because removing the element will cause the constraint to be implicitly removed before you can save it.

Starting in OS X 10.10 and iOS 8.0, I was intrigued by the announcement that NSLayoutConstraint now supports a property called “active,” which can be used to, you guessed it, activate or deactivate a constraint. I assumed this would be an answer to my prayers: a constraint could now be left installed on a view for safe-keeping, but its impact on layout would be negated by setting it to be “inactive.” I envisioned setting up competing groups of constraints on a view and simply activating or deactiving them en masse when the need arose.

I assumed wrong.

Looking at the documentation more closely, I see the description of what the method actually does:

Activating or deactivating the constraint calls addConstraint: and removeConstraint: on the view that is the closest common ancestor of the items managed by this constraint. Use this property instead of calling addConstraint: or removeConstraint: directly.

The rub is that an NSLayoutConstraint whose “active” is set to false will be removed from view it is installed on. So if you have any hopes or dreams of reapplying that constraint later, you’ll need to save it somewhere, just as before. If you don’t keep a strong reference to the constraint, it may be deallocated. If you tried to go back and set “active” a constraint that you referenced as a weak IBOutlet, for example, it would be nil by the time you tried to do so.

The OS X 10.10 AppKit Release Notes makes a clearer emphasis on the intended utility of the “active” property:

Under Mac OS X 10.10, it is now possible to directly activate and deactivate NSLayoutConstraint objects, without having to worry about adding them to an appropriate ancestor view. This is accomplished by manipulating NSLayoutConstraint’s new boolean property ‘active’. Class methods are available for operating on multiple constraints simultaneously, which can be much faster. The legacy API on NSView for adding & removing constraints is now deprecated.

So “active” is not a convenience for easily toggling whether an installed layout constraint has an effect or not, but a convenience for the plumbing of installing and removing them. The emphasis on adding and removal API being deprecated especially underscores that.

Having written this all out, it suddenly occurs to me that the “active” flag I was dreaming of is actually sort of available, and has been all along. Because NSLayoutConstraint supports a mutable “priority” property, you can effectively disable it by setting its priority lower than any other constraints that affect the same view. One caveat though is you can’t change a constraint’s priority to or from “required” at runtime, so you have to choose a priority lower than 1000. Something like this should work:

NSLayoutPriority newPriority = activate ? 999 : 1;
[dynamicConstraint setPriority:newPriority];

So long as a set of counterpart constraints affecting similar views is always prioritize to the inverse when toggling state, something like this should work™. Of course, it requires knowing the “active” priority in code. If a given disabled constraint should actually have priority 501 or 250, or whatever, then you’d have to save that priority somewhere. In which case you may as well go back to saving the whole constraint.

Mac App Store Sandbox Testing

For months, many of us Mac developers have noticed that apps built for Mac App Store submission could no longer be tested using iTunes Connect “sandbox” users. Previously, a sandbox user account could be used to authenticate and download a _MASReceipt for a Mac app, to ensure that in-app receipt validation is working as expected. After updating to 10.11.2, many of us noticed that this functionality suddenly stopped working:

At first, we assumed it was a bug. But as time went on, it started to seem as though it could be related to Apple’s announcement that one of its key certificates was expiring.

Still, the communication from Apple about this issue was poor enough that it wasn’t obvious what exactly we needed to do. Even though the page linked above has a section explicitly listing what Mac developers are expected to do:

You can verify your receipt validation code is compatible with the renewed certificate in the test and production environments. A pre-release version of the Mac App Store Update for OS X Snow Leopard beta is now available.

The linked “pre-release version” was no-doubt once a valid link, but at least through my account, it now leads to a permission-denied type failure page.

So what do we do? Fortunately, after chatting through the problem with some friends, Chris Liscio deduced the key, somewhat-obvious in retrospect steps to test your Mac app for compliance with the new certificate, while getting sandbox testing working again at the same time:

  1. Install the new certificate from Apple. In my case, I opened it in Keychain access and added it to the System keychain, where the older, expiring certificate currently resides.
  2. Reboot.

The second step is the important one. If you just install the certificate and expect everything to work, you’ll be sadly rebuffed with continued failures. Reboot. Let the system soak in the new certificate, then try re-launching your Mac app built for submission to the Mac App Store. It will prompt you, as you had previously expected it to, for your sandbox credentials. When you enter them, instead of insisting you set up a new iTunes customer profile, it will just launch. Or, if it doesn’t, maybe you’ve got some problems to work though in your receipt validation code.

Unsteady Platform

I ran into a vexing build failure with one of my iOS integration builds. The vast majority of everything in my complex project, consisting of dozens of dependencies, has built fine, but at link time things blow up because one of the dependencies is not of the expected architecture.

Undefined symbols for architecture armv7:
"_RSIsEmpty", referenced from:
-[RSFormattingMacro emptyMarkupPlaceholders] in RSFormattingMacro.o
ld: symbol(s) not found for architecture armv7

Ugh, huh, wha? How is this happening? It turns out the library in which “RSIsEmpty” resides, RSFoundation, is being linked to, but it’s opting for an OS X version of the library instead of an iOS one. Because this is an integration build that performs a number of related builds for both Mac and iOS, it makes some sense that I would have both an iOS and OS X build result in the build folder. But even if I have built copies for either architecture, why is it opting for the OS X version on an iOS build?

I decided to blow away all the built versions of RSFoundation and try the build again. This time, I got an even more perplexing failure:

clang: error: no such file or directory: '[...]/build-Integration/Release/RSFoundation.framework/RSFoundation'

I’m scratching my head. Did it somehow get removed as a dependency? But then I notice something subtle. It’s looking for the framework in the “Release” build folder, but for my iOS build it should be looking in “Release-iphoneos”. What the heck is going on?

In spite of the sole build target in this scheme being an iOS app, Xcode (actually xcodebuild) is opting to build this scheme with a default destination of OS X. I don’t know of a direct way to get xcodebuild to list the available destinations for a scheme, but I know that if you pass a bogus destination platform, it will do the honor of listing its impressions:

xcodebuild -destination "platform=xx" -scheme MyIPhoneApp

The requested device could not be found because no platform could be found for the requested platform name.

Available destinations for the "MyIPhoneApp" scheme:
		{ platform:OS X, arch:x86_64 }
		{ platform:iOS Simulator, id:6DF04FFC-1C8A-4745-8F8C-7369E9CBF8DB, OS:9.3, name:iPad 2 }
		[... every other iOS simulator on my Mac ...]

Aha! So it thinks my iPhone app is suitable for OS X. But why? After a great deal of experimentation and poking around, I discovered the root of the problem is summarized by this true statement:

If any target in a Scheme’s dependency tree targets OS X, then the scheme itself will also be considered to target OS X.

In retrospect, this explains the problem perfectly. I had recently added a subproject to my dependency tree that builds both an iOS and a Mac version of a library. That’s fine: it works pretty well these days to allow targets for differing platforms to coexist in the same project file. But each of these targets also shares a dependency on a single, legitimate OS X target: a helper tool used in the process of generating that project’s own source files.

This must be at least a relatively common scenario for iOS builds of certain complexity. Because the platform on which all iOS builds run is OS X, any helper tools that are compiled and used in the process of generating sources or otherwise processing build materials, must be built for OS X.

The workaround to my specific problem is to specify a platform explicitly on the command line. I can’t assume that because the scheme targets iOS, it will necessarily default to an iOS platform target. I consider this a bug, not only because it led to this difficult to diagnose build error, but because it has other ramifications such as the presentation in Xcode’s scheme popup for these projects a useless, distracting “My Mac” target which should never be selected for the schemes in question.

I filed this as Radar #24247701: A scheme whose target has dependencies on another platform shouldn’t “support” that platform.

A Eulogy For Objective-C

I missed Aaron Hillegass’s talk at AltConf earlier this year, but was nudged to take a look at the transcript by Caro’s tweet today linking to the talk’s video page on Realm.

Although I’m 100% sure, based on experience, that Aaron’s talk is a pure delight to watch, I also appreciate that I could jump right in and read a transcript of the talk until I get a chance to watch it. Aaron gives a thought-provoking “eulogy” for Objective-C, in which he celebrates its parentage and its life thus far.

When a guy like Aaron Hillegass gives a history of Objective-C, and speaks to its strengths and weaknesses, you should hang on every word. He covers many of the features that distinguish the language, provides a context for when they were added, and gives examples of key technologies that are enabled by them. He is also aware of the tradeoffs some of these features demand:

Loose typing made a lot of things that were difficult in other languages much easier, or possible. It also made bugs that didn’t exist in other languages possible as well. And you embrace that as an Objective-C programmer. You’re like, “This is a language for smart, pedantic, uptight people, I’m going to be very careful and do the right thing when I’m typing in names.

I love his hypothetical quote, and think it condenses the feeling a lot of us long-time Objective-C programmers have about the language. We welcome Swift in many respects, but it’s hard to let go of a language whose idiosyncrasies we’ve grown to love, hate, and ultimately make peace with.

WebKit Hacking From The Bleeding Edge

As the developer of an app that depends heavily upon Apple’s WebKit technologies, I have often been grateful that the software is open source. It is by no means easy to wrap one’s head around, but when faced with a vexing problem, I can browse, even build and run a custom copy of WebKit on my system, to step through code and try to reason more clearly about its behavior. I’ve even filed my share of bug reports and patches.

While I am very interested in the evolution of WebKit, I am even more concerned with the evolution of OS X. For this reason, I typically install OS X beta releases far earlier than many of my colleagues. This gives me the opportunity to work day to day with the latest changes coming from Apple, and makes it that much more likely I will spot issues with my apps, concerns with the OS, etc., before my customers do.

As an open source project, I initially believed I could build and run WebKit wherever I choose. After all, isn’t that what “open source” is supposed to be all about? But ah, there’s a catch. At least when it comes to building and running WebKit on OS X releases, there is a dependency on a small, binary-only static library which provides key system-specific linkages to WebKit. Usually this binary is added to the open source project around the time the system release goes public, but not much sooner.

The long and short of it? If you want to build WebKit and you don’t work at Apple, you need to do so from publicly released versions of OS X.

For years, I have found this personally annoying, but also philosophically distasteful. It seems like a problem for Apple, too: it’s in their best interest to have as many WebKit developers as possible staying up to date, building the latest versions, testing, submitting patches, etc. And it’s in their interest to have as many OS X developers running the latest betas of the OS, providing feedback, preparing their apps for the public, etc.

A single developer, with a single Mac, running a single installation of OS X cannot simultaneously be a diligent, interested WebKit developer and a dedicated OS X beta tester. This seems like a problem to me, so I finally reported a bug. Radar 21703162: “Beta OS X releases should facilicate building/running WebKit from source.”