If you can’t tell from my last entry and the solid stream of profanity coming from my Twitter account, I’ve been coding a bunch lately. I’ve never been good at coding an hour or two here or there. I tend to code the fuck out of some big hunks of time, which makes me cranky. Throw in the bout of Cambodian dysentery I am recovering from and I am in a bloody shitty mood.
Luckily, swearing is how one prays to the Gods of Engineering, and they have rewarded my suffering. In order to regain some of the karma I just pissed out all over my good friends on the AppKit team, I am sharing this knowledge with you. If you’re really lucky, Google’s recent attempts to get their shit together on search will pay dividends by the time you run into this bitchy cabal of bugs.
I’ve been dickslapping around an NSScrollView for a while, giving it the works—custom scrollers, custom rulers, and all kinds of wacky-assed layer-based content. As with any custom UI work in AppKit, the biggest enemy is glitchy drawing, and in chasing down some of those, I came across a bit of documentrivia regarding layer-based content in an NSScrollView.
It seems NSScrollView isn’t completely hospitable toward layers unless the scrollview itself is layer-backed. Finding that out was like finding out all my problems could be solved with one line of code. In fact, it was exactly like that.
hellYeahScroller.wantsLayer = YES;
That’s a line of code even a hooker can love, and wouldn’t you know it, all my drawing problems magically evaporated like scotch whisky. I licked my lips in anticipation of that sweet, sweet push to version control, but first I had to Shipley my code by testing it like I caught it stealing my car.
It didn’t take long before all hell broke loose. It was like realizing that glass of celebratory scotch is Johnny Walker red or, worse, Irish whiskey. Turning on layer-backing in the scrollview turned out to be the chemotherapy of cures, causing far more problems than it solved. Most of them seemed to be coordinate-based, but the really disturbing thing was what it did to my rulers.
Unleashing Core Animation on NSScrollView fucks up your rulers faster than you can say “Michael Jackson.” My markers stumbled around as if drunk of methanol, my hash marks looked like a British person’s teeth, and my labels appeared to float about at random asking, “What’s happening? What’s happening to us?” The origin itself seemed to shimmy and shake, and not just during today’s 60-second earthquake.
I assumed, naturally, that this abomination was completely my fault. Aside from the fact that I was using a *dundunDUN* custom NSRulerView subclass, bugs are always your fault. Actual bugs in the framework account for an infinitesimal percentage of bugs, and even if there is a bug in there, you’re the one who pissed it off.
Although that assumption turned out to be wrong, making it was not my mistake. No, my mistake was spending countless hours chasing it through the labyrinthine codebase. I am a bit of a grinder, and I will sit there and grind on a bug the way people on Grindr will grind on pretty much anyone else on Grindr.
What I should have done in the first place was what I eventually did do, hours of tooth-grinding later, which was to isolate the bug in a trivial sample project. You think that’s going to end up being a waste of time, but in mere minutes I figured out that there was fuck all I could do about the problem except for the most important thing to do when you find a bug like that, which was to report it to the platform vendor, in this case Big Fruit.
There are two inviolate laws when it comes to reporting bugs. The first one is always, always include a trivial sample project that demonstrates the bug. For things like OS bugs you can include a screencast, but for bugs in your app, you have to isolate it in a reproducible fashion for the receiving team if you want to guarantee results.
The other rule is this: don’t swear in your bug report. You can swear about your bug report, but don’t swear in your bug report. Like your comments and your commit logs, you want to keep that shit above board and completely professional.
OK, I will admit to sometimes trying to make the people reading the bug smile—I used the phrase “scroll it like you stole it” in this one—but it will do you absolutely no good to piss them off.
Not only that, but titling your bug something like “NSRulerView: you are fucking killing me with this” or “Core Animation completely fucking gang rapes NSScrollView” is not helpful. These titles do not contain any real explanation of what the problem is, other than that you are a dick who is bad at writing bug reports.
It’s important to file those bugs, even if they get marked as dupes, and even if you know the team responsible is—or should be—fully aware of the bug. The people who build and maintain frameworks have bosses who say things like “why would we spend time on something nobody wants?” and the only answer the good guys have are the mountains of bug reports we send them.
Bug reports not only inform and assist, but empower change. Then and only then should you bitch about it on Twitter. Then you might still be a dick, but at least you’re a dick with a bug number—in this case <rdar://problem/8942818>—which puts you in the top percentile of dicks who bitch about bugs on Twitter.
How about a reachworkaround?
Luckily the Gods of Engineering heard my prayers, and shortly after coming to the conclusion things were hopeless, I had a sudden flash of insight, tested it out, and had a hallelujah serviceable workaround. Instead of one line of glorious code, use two:
hellYeahScroller.contentView.wantsLayer = YES;
hellYeahScroller.documentView.wantsLayer = YES;
By turning on layer-backing for the scrollview’s content view (AKA NSClipView) and its document view (AKA the offending view), Core Animation’s drawing glitches are squashed, while the ruler view and all its madness are left safely alone. This works regardless of whether you are using a plain old NSRulerView, or a subclass thereof.
The only thing left is to give it back to the community, which I have just done. As an added bonus, here is a slightly spiffed up version of my test case: LayersLemursRulersOhMy.zip
Happy trails!
Bug reports not only inform and assist, but empower change.
Tuesday, February 1, 2011
Layers + Ruler = Swearing