Summer Xcode Tips

June 22nd, 2006

It’s summer! The sun is out and the sky is (leans right to peek outside), well, sort of greyish. While the world celebrates the changing seasons, we’re all leaning over our keyboards and squinting into the screen, working on our LCD tans. All this warm weather puts me in the mood for Xcode tips! I’ve been saving up a few “gotta share” revelations. Are these tips no-brainers? Maybe for some of you. But it took me a while to “get it” and I’m hoping some of you will also giggle with glee when you learn out about them.

Hint #1: Double-Click to Open in External Editor

As my projects become more complex, they inevitably become the gathering place for an assortment of file types that support the production of and testing of the final product. Most of these files are source files, and Xcode is good at editing them. But others, such as scripting definitions and carbon resource files, are best left to external editors. Unfortunately, there are a number of file types that Xcode thinks it’s a good editor for, when it really isn’t. Even some source files might be better edited by external applications, depending on the particular goal.

I’ve spent a lot of time right-clicking such files and selecting “Open in Finder” from the contextual menu. This has the desired effect of opening the file in whatever application you’ve specified as the file’s owner via the Finder. That’s not a bad solution, but it’s slightly annoying, and not nearly as streamlined as double-clicking. But when I double-click a typical file that Xcode claims understanding of, it opens in a separate Xcode editor window. Ugh! I wanted to open in the external application!

From the “File Info” window in Xcode, you can tell Xcode what type you want it to consider the file to be. This is handy for things like making it apply Objective-C++ rules to a “.m” file, but the list of file types it’s prepared to acknowledge is really vast. As I set out to convince Xcode to open my file with another app, I thought I surely needed to teach it more specifically what kind of file it is. It’s not a text file, it’s an XML text file. No dice. Xcode “handles” that, too.

The answer to this problem is surprisingly simple, but it requires counter-intuitive (to me) reasoning. Instead of being more specific about the file’s type, you have to be less specific. Among the myriad choices is an item called simply “file.” When a file’s type is “file,” what do you know, it opens up with the Finder when you double-click it.

Note, if Xcode has already “laid claim” to being editor of your file, it probably has an open file reference to it somewhere. It will not give up its role as editor until you close the file. You can do this by choose “Close File [Blah]” from the File menu while the file is focused, or by pressing the shortcut Cmd-Shift-W.

Hint #2: Eliminate Build Configuration Strain

Since Apple announced the transition to Intel, quite frankly the hardest development aspect for me has been keeping all the darned build settings straight. If you are willing to target 10.4 and later, things are pretty straight-forward. But if you live in the real world and need to continue supporting older release of Mac OS X, things get trickier. To support earlier than 10.3.9 and Intel in a single universal binary, you have to use separate compilers at a minimum, and probably separate SDKs as well.

If you’ve had to do this for one or more of your projects, you probably got used to locating, copying and pasting the build settings from one project to another. Yuck! Not only is this prone to error, but it is “stupid work” that takes up a lot of time and energy. Apple’s answer to this problem is the “.xcconfig” file, which allows you to specify a number of baselines build settings outside the scope of a build configuration.

These “.xcconfig” files are simple text files containing variable names and their desired values. For instance, here are the contents of a baseline file I use for “Universal builds that need to run on 10.2”:

ARCHS = ppc i386
SDKROOT_i386 = /Developer/SDKs/MacOSX10.4u.sdk
SDKROOT_ppc = /Developer/SDKs/MacOSX10.3.9.sdk
GCC_VERSION_i386 = 4.0
GCC_VERSION_ppc = 3.3
MACOSX_DEPLOYMENT_TARGET = 10.2

I call this file “Universal 10.2+” and keep it in a common location accessible to all of my projects. Now when a particular build configuration in any project needs to “inherit” these settings, I use the “based on” feature of Xcode’s build configuration system. You simply drag a reference to the “.xcconfig” file to your project, whereupon it becomes available in the appropriate popup menu:

Notice that in this case I’ve chosen to name the “inheriting” build configuration “Release 10.2+”. There is a method to this madness: by adopting a naming convention for build configurations that match the system requirements, I can easily ensure that libraries from dependent projects get built under the same settings. By using a consistent naming scheme, and pointing all such build configurations at the same “based on” configuration file, I can rest assured that changing the settings in one place will percolate out to all the affected targets.

Also notice that “Architectures” is not even set by the project (it would be bold if it were). The setting of “ppc intel” comes from the configuration file. The project yields responsibility for defining what “Universal” means. So if Apple adds the rumored support for the Z-80 processor, I’ll only have to change the settings in my “.xcconfig” file.

I’ve barely scratched the surfaces of these files’ power. On top of the “based on” notion from Xcode, the files themselves can also explicitly include other files to stack a great deal of common build-setting definition into your process before the project-specified configurations are even reached.

Hint #3: Install a Directory of Changing Supporting Files

Let’s say you’ve written an application with an awesome templating system. You allow your customers to write their own templates and use them as the basis for new documents. To get your users off to a good start, you include a bunch of built-in templates in your app. In fact, your system is so good that there are literally hundreds of built-in templates and you’re adding more in every release.

All you want Xcode to do is put your directory full of “Built-In Templates” into the resulting application’s “Resources” directory. If you’re like me the first thing you think of doing is simply adding the directory of templates to Xcode, and then dragging the resulting folder icon to the “Install Bundle Resource” build phase. After all, that’s what this standard build phase is for, right? Yes. But the standard build phase does something annoying. Instead of copying the directory to the resources folder, it copies each individual file over to the root of the resources directory. This makes for a very cluttered resources directory.

The good news is that a simple “Copy Files” build phase of our own can get the job the proper way. Just add a custom build phase to your target with target directory “Resources”, and copy your folder reference to that. For some reason the built-in resources phase is “smarter” than it perhaps should be.

Note: When you add your directory filled with templates to the Xcode project, make sure to check the box that requests “folder references” be created. This is how you tell Xcode to take the folder as it is at any moment. Instead of adding the contents of the folder to the project as a group, it will dynamically refer to the contents of the folder as they are at any time. Now when you add new templates to the folder, they’re automatically copied into the app’s resource folder when you next build.

What a Difference a Cell Makes

June 17th, 2006

I’ve been bothered for a long time by a limitation of NSTextFieldCell that prevents developers from specifying a vertically centered alignment. This is particular annoying in contexts where Apple practically rolls out the red carpet for a particular UI feature, but where taking advantage of that feature is almost guaranteed to produce an ugly result. Take NSTableView for example. What is the most common cell type in a table? NSTextFieldCell of course. But what happens when you add the slightest bit of creativity to a table, say by changing the row height to a value not suited to the font size?

That’s bad enough, but let’s say you find good reason to reach for even taller table columns? It can only get worse from here:

In the past I’ve just worked around this problem by finding another way to present my UI. In other words: just keep the freakin’ table view rows shallow, or else live with the funny looking top-alignment of the text. Today I got fed up with that and decided to shoot for a general-purpose solution.

I didn’t want to implement my own completely custom text cell. NSTextFieldCell is pretty good, you know! It does a lot for me, and I’d like to continue taking advantage of that. Through a bit of experimentation, I discovered that I could make a pretty minor tweak to NSTextFieldCell and get the behavior I wanted. By overriding “drawingRectForBounds:” and returning, instead of the whole lot of real estate available to me, a centered subset of that area, I convinced AppKit to render the text in the middle like I wanted it:

Hey! That’s looking a lot better. I like it. It looks pretty. You know, like a Mac. But you know what doesn’t look pretty? When I double-click this bad boy and try to edit the text:

Ouch! That’s a pretty freaky looking user experience. Apparently NSTextFieldCell or some other component of AppKit is not used to having the drawing rect drastically adjusted without its knowledge. I might have to call this whole deal off. However bad top-aligned text in my table cell is, it’s a bajillion times less offensive than that. But then I realized that as a cell, I am given a lot of control over the edit process. What if I can limit my rect adjustment so that it’s normal while we’re editing, but weird (i.e. good) all the rest of the time?

I added two methods to my custom subclass, overriding “selectWithFrame:…” and “editWithFrame:…”. In these methods, I use my rect calculation method to transform the proposed edit or selection rect into the more desirable “centered rect,” then I set a flag in the class “mIsEditingOrSelecting” which tells my rect calculator to stop the funny business. The result is an NSTextFieldCell with very little code that, as far as I can tell, behaves appropriately in all circumstances:

Good enough for beta software! But here’s where you come in. You want this sexy vertically aligned cell for your app, right? So let’s share and figure out whether it’s monumentally busted or not.

Download RSVerticallyCenteredTextFieldCell. MIT License. Pop it into your project and, upon waking from nib, set your text column data cells (or other text field cells, if you have good reason) to instances of it. Let me know if you spot any bugs!

Blog Redesign

June 15th, 2006

I’ve noticed that people are slowly discovering the new design of the blog. I meant to write a post about it when I “made it live” a week or so ago, but I have been putting it off for some reason. I think I didn’t want to waste a whole post on talking about my new design, without giving some interesting facts about how NodeBox facilitated and inspired the design. Anyway, this is the story of how I liberated myself from Kubrick! (The default WordPress theme). In fact, my blog has been so “vanilla” in its design for the first year of its existence, that it may be inappropriate to even call this a redesign. Short of picking a color, this is about the only design I’ve ever done for it (and apart from the banner and some minor CSS tweaks here and there, it’s still Kubrick at the core!).

The Story of the Banner

I was playing with one of the NodeBox libraries called Pixie, which is designed to make simulated “scrawled writing.”

It even includes some crazy “doodles” where it creates pseudo-random sketches of creepy little guys. I made this example wallpaper using a grid of creepy guys:

Finally I played with the crazy “graph generation,” which is a feature by which a nearly illegible graph is produced based on a specified list of nodes. You can only play with stuff like this for so long before you start indulging the ego. So I plugged some blog-oriented text in:

I decided to play with the little scribbled circles, add some color, and put them in a grid format with some blog-oriented text in them.

Pretty! Did I mention I love NodeBox? By now I was starting to theoretically consider my playful tinkerings to be the possible basis for a new blog banner. So I decided to pick a more realistic layout for a banner.

This is starting to look pretty cool. But I came to terms with a couple facts. First, the scribble look is cute but doesn’t give a clean appearance that I want to associate with my blog and business. Second, I better stick with a red color scheme unless I want to change the name of the company to AquaGreen Sweater Software.

I had already toyed with plain circles as a means of giving the text in the design a little pop and stability. So I thought I’d just abandon the scribbles and use all perfect circles. The logic behind the generation is basically this:

  1. On an NxM grid, randomly choose whether to render a circle or not.
  2. If a letter is to be rendered at a given location, a circle is always rendered in a particular color (opaque red).
  3. For all other circles the color is rendered as a randomly color in the red ballpark.
  4. Letter locations are “nudgeable” by an array of x/y nudge parameters.

After much tinkering, I ended up with a solution that was close enough that I did a few finishing touches by hand and called it done. But I liked the results so much that I started almost immediately thinking of doing a similar design for the Red Sweater Software home page. This time I decided to make it all work from code the way I wanted it, and am therefore able to randomly generate new banners at will. The quality of these sucks but it’s just because I scaled and converted them for easy demonstration in the blog. Not every one has to turn out perfect – with NodeBox I can just run it until I see a result I like. The balance of colors and placement has to be nice. In my script I am also able to “guarantee” a certain spot to be a circle, so I can enforce some positional balance as I desire.




One of the unexpected outcomes of all this experimentation and incremental design was that NodeBox helped me get comfortable with the idea of pink as a fundamental design color for my site. I don’t think I ever would have thought of using pink unless I just stumbled upon it as a variation on red. I know, silly. But it’s a fantastic realization because I’ve long had a hard time designing (such as I do) with red. It’s so strong, it’s hard to use it without overpowering the reader. The pink elements in the new design, along with the drab gray background, I believe give me some leeway to get away with the bold red while sparing the reader from saturation overdose.

Tangentially…

While I’m talking so much about NodeBox, I should mention some other cool tricks I’ve discovered. It can be fun to play with rendering text while adjusting some random number of the text’s vertices on the bezier path. This is pretty naive adjustment, just tweaking the location of a vertex here and there, but produces a dramatically “unique” look:

And finally on a more practical level I decided to use NodeBox to design some new toolbar icons for FlexTime.

Now, these icons are nowhere near the quality you’d get from an excellent designer, but they’re much better than I would probably come up without NodeBox. It makes me so comfortable to have programmatic cnotrol over the rendering. A whole palette of buttons and I have source code to them! The nerd’s design tool. This simply inspires me to be more creative than I am manipulating control points with a mouse. Seeya Illustrator, wouldn’t wanna be ya!

So yee haw and three cheers for NodeBox, right? Sort of. The bad news is that I know it well enough now to be utterly disappointed by how much more it could let me do. The toolbox is pretty minimal, and exposes only a small fraction of even the basic path manipulation tools provided by Quartz. The documentation is also lacking and I find myself frequently discovering new tricks that are part of the code but simply not publicized. NodeBox is the beginning of something pretty amazing, and I’m excited to see where it leads. If this keeps up, I might end up influencing that direction by writing my own NodeBox libraries. It’s definitely as fun as most work gets.

Another UI Bites the Dust

June 15th, 2006

It’s been a little while since I critiqued (or mercilessly attacked, depending on your perspective) an application’s UI. Actually, it hasn’t been that long at all, but I just downloaded and tried the Mac OS X version of Meetro, and we might as well learn from some of their successes and mistakes. Let me just warn anybody loyal to Meetro that this entry will not be high-fives all around.

Like most things in life, it’s easier to spot the mistakes after they’ve been made. I’m sure that anybody looking at the products of my labor would spot problems that I just gloss right over because of my familiarity with them. The criticisms are just my opinion, but they are opinion formed from a long association with the Mac and with understanding pretty well how things are conventionally done. When I see an application with elements that stand out like a sore thumb, I try to learn from it. What could they have done differently to make this application more usable and attractive? Hopefully both Meetro’s authors and the Mac developer community can learn with me as I go over some of this application’s less desirable points. By learning and reinforcing our conception of what makes a good application, even less successful application releases can provide us with some service.

I think I started out in a bad mood because I clicked the big “Download Now!” image and expected to start downloading. Call me crazy but when I see the words download I think of files coming to my computer, not filling out an enrollment form. The image should read “Register Now!”

But I was curious so I went through the registration. Soon enough I was looking at a very pretty DMG mounted on my desktop:

Cute! Nice retro font. Bubbles. Whee! Note the exclamation point at the end of the install advice: it’s a foreboding warning of intensely enthusiastic phrasing soon to come. My only criticism of the DMG is that it asks the user to drag the icon to the Applications folder, but doesn’t offer them a convenient alias to it. At some point within the past few years, some genius figured out that you can put an alias to the Applications folder right on your DMG, so the user doesn’t have to fish around for the folder to perform the drag. I think I first saw it in Fetch, but I’m not sure if that’s where it originated. At this point, it’s caught on enough that I’m disappointed when an application doesn’t have it. At least if you’re not going to have one, don’t emphasize the folder in your advice. Omni products for instance don’t have the convenience, but they at least let the user know that you can drag it anywhere you want to. Lesson: Make it mind-numbingly easy for the user to perform the expected action.

Upon first launching Meetro, it presents a login dialog, similar to what you’d see when running any other chat program:

Pretty nice looking. I might make some little tweaks, but at least it flows well and has a pretty good balance. Now for the numerous nits to pick. The “Status” box looks kind of PC-ish to me, why not just use a static text? Worse: clicking on the text makes it disappear. The group box is probably unnecessary but if it’s used I would like to see an equal amount of whitespace on all sides. The unconventionally narrow margin at the bottom seems to work with the streamlined look of the floating dialog, but what’s with the fat margins on the sides? The dialog has a close box but clicking it doesn’t do anything. Is “screenname” a word? Finally, take note of the number of exclamation points in this dialog: more foreboding! Lesson: Comply with standard Mac UI unless another technique improves the user experience.

But the real problem with this dialog is what happens when I enter my information and click “Log me in!” It doesn’t log me in!!! ZOMG! Now if I’m a normal user I have to sit here and wonder what the hell happened. But since I’m a nerdy user I pop over to the Console to see if the application has spewed anything informative to the standard output. Sure enough, a number of debugging strings have been presented, culminating in:

LLNETNetworkThread: no data received in 65 seconds. Assume disconnected
LLNETNetworkThread: unforced disconnect detected. Do full disconnect, then re-connect!
LLNETOpenConnexion: successfully connected to server 0

So I’ll give Meetro the benefit of the doubt and assume they’re having a bad server day. But this condition was detected so beautifully by the code, only to be trapped inside the application and never conveyed to the user. What was the point of all that careful error handling if you’re just going to leave the user hanging? Even something vague like “There was a problem connecting to Meetro, please try again later” would give me some clue. Lesson: Translate runtime exceptions into meaningful error messages the user can act on.

While I was looking at this failure to login, I thought I’d follow-up on what a regular user might do in such an event. The Help menu beckons.

OMG!!! I totally need help. In fact the severity of the application’s failure right now makes the extreme enthusiasm sort of appropriate, but in general it’s not polite to add such enthusiasm to verbs. Let the user decide whether the amount of help they are seeking is “three-bang level” or not. Users like to have unemotional control over their their tools. Can you imagine how ridiculous it would be if all the other devices you use had exclamation points following all the verbs? Honey, we should totally watch TV!!! Yes, I will get the remote!!! Wait, how do I turn it on? Oh Yeah! Just press the “On!!!” button. As a developer, when in doubt, just look at what every other application of note does. Have you ever seen a “Help!!!” menu item before? Lesson: Use emotion-agnostic language in your UI. Don’t attempt to artificially depress or excite the user.

Again, the real problem is what happens when I actually select the help menu item. I’m taken to a web page called the “Meetro FAQ.” OK, fair enough. This is online help. But looking around I can’t help but notice that this is a general purpose FAQ, not one specific to the Mac client. I click on “Platforms” where I finally see mention of Mac OS X. It’s from December, 2005. The good news is that an alpha version is ready for testing. The bad news is that I still seem to be testing it now in June, 2006. Lesson: Lead the user to Help that is highly pertinent or else don’t lead them at all. Don’t bait and switch!

While we’re looking at the Help menu, let’s try out some of the other options. Maybe, even though this product was just announced, and I’m running it on the day of its announcement, I somehow have an outdated buggy version? That option to “Download latest version” looks hopeful. I love it when applications help me stay up to date. But selecting this option does exactly what it says it will do, it links directly to a dmg download, which on my machine causes Safari to start re-downloading the version I’m already running. I don’t need it if it’s the same! Thanks, though. This situation would be made better by using Andy Matuschak’s free Sparkle framework or Tom Harrington’s cool SparklePlus branch, which allows for optional collection of a user’s machine statistics. Since Meetro includes the Growl framework, I know that the company is not averse to open source solutions. Lesson: Empower your users by incorporating de facto standard open source packages. Don’t reinvent the wheel badly.

The “Changelog” menu item doesn’t read well. I’m used to seeing verbs and suddenly I see a noun. How about “View Changelog”? At any rate, when you select it, it takes you to a web page documenting the entire history of the application in all its informal glory. The latest entry is most telling:

v0.51 - Em ti, mprikia kollame; (2006/6/15) - md5: 1b9122f9a9d73037cc923e71545d0172
--------
coming after I wake up, coz I REALLY need sleep (6am)

Ouch! Sorry, whoever you are, and I hope you have a nice rest before waking up to discover that users can’t connect to the service and some snarky blogger just dissected your app. What can we learn from this? The author was so busy and sleep deprived trying to get this release finished that he or she couldn’t even copy/paste the notes of what was changed. This is probably a bad sign for the overall readiness of the release. Lesson: When in doubt, delay the release until adequate testing can be done. Actually, we get two lessons from this one! Lesson: Don’t publicize embarrassing details about your last-minute race to release the application

All told, the Help menu really didn’t help me at all. I still can’t log in and I don’t know whether it’s a problem with the whole service or just with my account. I tried a few more times by quitting and restarting the application, and then decided to check for the possibility of a pertinent Preference item. The Meetro Preferences are reachable through the conventional location, under the application’s self-titled menu in the menu bar:

Whoah, crazyville! What are all those items doing in there? You could argue that Meetro is being innovative here and simplifying the user experience by putting everything the user may need to do in one centralized location. The items listed here even seem somewhat consistent with Apple guidelines as they are “items that apply to the application as a whole.” But that doesn’t matter, because nobody puts this much random junk in the application menu. If there’s going to be a change in the tide, I don’t think Meetro is going to be the one to do it. I see this kind of stuff from time to time, where a developer will point out that their highly unusual UI is actual “according to guidelines.” But if nobody else’s applications interpret the guidelines in that way, you’re doing a disservice to users by bucking the system. In the real world, this application should probably have a “Chat” menu or something that houses these related-yet-global items. Lesson: Favor real-world trends over literal interpretation of Apple design guidelines.

Don’t think I’m done with that menu yet. Not matter where it lives, it’s got problems. What stands out in this menu and in the Help menu is the decision by Meetro to shun the conventional capitalization of words in a menu item’s title. You don’t have to look any further than the very menu these items live in to see instances of “proper” capitalization. “Hide Others” and “Show All,” for example. If that’s not enough, look in any menu of any application on your Mac. The lower-cased words in Meetro’s menu items stand out like sore thumbs! On the Mac we capitalize lots of words. It’s like a headline. I can’t imagine just not noticing that every other menu item on the system looked different, so I have to assume this was a conscious decision on Meetro’s part. Do they think their menu items are more correct? Maybe on a PC. Lesson: Do things the Mac way even if you feel it’s the wrong way.

I can’t help but notice that they’ve claimed some awfully ubiquitous keyboard shortcuts for some of their menu items. On a Mac, Cmd-S means “Save” and Cmd-P means “Print.” It’s really confusing to a user for these shortcuts (and Cmd-C, Cmd-V, etc) to be used for anything else. What’s funny here is obviously Cmd-P was claimed for “Photo,” but why was Cmd-S claimed for “Open drawer profile”? And what does that even mean? I assume they meant to call the item “Open Profile Drawer.” Lesson: Avoid conflicts with universally-known keyboard shortcuts.

At this point I’m getting pretty lonely because I still can’t login. So I decide to play around with these menu items. Maybe I can sneak onto the Meetro network through the back door. Whoops! Another UI defect, I mean lesson. Although these menu items are enabled, most of them do nothing in my current state. I thought maybe changing my location or trying to “reset the user” would tickle the system and let me in. But each of them just does nothing. Ditto for all the items, with the exception of “Invite friends.” More bait-and-switch! Lesson: Always disable UI elements that, when selected, will do absolutely nothing.

So what happened with the one item, “Invite friends,” that actually did something? It took me to a web URL where supposedly I would be able to, you know, invite some friends or something. Instead I found the grandaddy of all bad UI: the 404 page not found error:

Page Not Found!

Hrmm... I can't seem to find what you're looking for!

Ouch! But at least it came with that charming Meetro exclamatory tone. Hrmm… we totally screwed up. Have a groovy day! The root of the problem here is probably during development there was a planned invite page, and when it finally got implemented it happened to reside at a different URL than originally planned. This kind of stuff is caught in that simplest of all QA phases: try every menu item once. Lesson: Triple-check external dependencies before releasing your application.

At this point I’ve written quite a lengthy tome and haven’t even been able to login to the service, yet. As I was writing this I hoped that by the time I got this far I’d finally be able to log in and would then see how the rest of the application’s UI stacked up. I suppose it’s a gift from the heavens that I wasn’t able to, since it helped to keep this entry at a nice manageable length.

There you have it, I’m excited to try Meetro and looking forward to a revised edition that lets me log in, among other things. In the mean time, I’m glad to have been reminded of some things to look out for while putting the finishing touches on the 1.0 of a forthcoming application. If I keep it up with entries like this, my product’s release will probably be met by a well-deserved round of criticism. And that will be a beautiful thing, because it means my 1.1 release will totally kick ass.

Update: I finally got logged in. I guess the server is just getting swamped today and the client app is not prepared to handle that very gracefully. Now that I’m logged in I can appreciate the innovative aspects of the application, but it’s a good thing I didn’t get logged in earlier or there’d be a lot more questionable UI to talk about.

I’m going to limit it to just two complaints: it should save my login information and my location between launches. It’s ridiculous to make me type my login when the system keychain is made for exactly this kind of thing. Lesson: Any value likely to stay the same forever, or for a very long time, should only need setting once.