cocoa

20 entries have been tagged with cocoa.

Typesafe typecasts

[The minimal sample code in an Xcode window]

This is probably obvious to everyone else out there, but since I only just realized this, I thought others may be similarly dense, so I’d like to point out a little bit of Pascal ingenuity that can be applied to a common Mac programming problem.

There are many classes and structs on the Mac that exist in duplicates. For example, CoreGraphics has CGRect to represent Quartz coordinates, while AppKit uses NSRect. They’re exactly the same in layout, but have separate names. Similarly, there are many toll-free bridged classes between CoreFoundation and Foundation. For example a CFURLRef can be used wherever an NSURL* is needed, as long as you typecast between the types so the compiler doesn’t whine.

Now, typecasts are dangerous: Assume you have an NSString* storing a file path, and now you decide to change it into an NSURL*, because that’s Apple’s new recommended type for file references. You change it in the class header, and all call sites start giving you type errors, which you fix.

All call sites? Nope. In one spot you were typecasting your NSString* into a CFStringRef. Now you’re typecasting an NSURL* to a CFStringRef, which is obviously wrong, but will only give you runtime errors. Ouch. So, what can you do? Well, there’s a neat trick that Pascal programmers used to use to get around Pascal’s refusal to typecast: They used a union. Unions are usually considered as type-unsafe, but in this case, they’re just type-safe enough for our purposes:

CFStringRef  UKNSToCFString( NSString* str )
{
    union ConversionUnion
    {
        NSString*      mNSString;
        CFStringRef    mCFString;
    } myUnion;

myUnion.mNSString = str;

return myUnion.mCFString; }

The neat thing is that this function type-checks the input and output, but since it’s a union, it lets us set an NSString* and get a CFStringRef. Our above change would cause a compiler warning now since we’re passing an NSURL* into a function that takes an NSString*. It encodes the fact that an NSString and a CFString are the same, but only those.

Apple even does that. Look at NSRectFromCGRect() (I slightly cleaned up the code):

NSRect NSRectFromCGRect( CGRect cgrect )
{
    union ConversionUnion
    {
        NSRect ns;
        CGRect cg;
    };
    return ((union ConversionUnion *)&cgrect)->ns;
}

They’re even a tad more efficient: Since the input parameter already is a CGRect, they just typecast it to a union ConversionUnion, saving you that one extra copy to an actual temporary local union variable. You could probably even get rid of the union completely and just typecast inside the function, as its input parameter type and return type already perfectly codify the conversion in a type-safe manner.

A neat trick for which I’ve created a header for a bunch of commonly bridged types and put it on my github.

Garbage collection, work of the devil?

I wrote before about how I learned programming the Mac using a scripting language, using its native API call plug-in scheme and how that made me realize that using scripting languages and their bridges to other languages or the native APIs (or even AppKit) is a great way for people to learn programming at their own pace.

Today, someone on an Apple mailing list complained that Garbage collection was

replacing one problem with two problems, one of which is the precise shape of the original problem

because the unpredictability of when garbage is actually collected means you are still forced to manually manage scarce resources instead of letting the object’s destructor take care of it.

That’s a very one-sided view: The advantage of Garbage Collection is not that it solves the problem, but that it partially automates the common case. If you don’t have to write a piece of code, you are less likely to forget writing it. And you are less likely to make silly mistakes (e.g. copying a release line, forgetting to adjust it, and then leaking one object and releasing the other twice).

In most of the cases, you don’t care when a particular object is actually released, as long as you can reclaim the memory it uses up when you need it. The cases where an object actually equates to a resource other than memory are a fraction of the overall number of objects you use: The property list types alone get created and disposed of so often that a mistake in there can easily introduce subtle bugs much harder to track down than realizing your hold on a device or file or other scarce resource hasn’t been relinquished.

People have programmed this way for ages. As above-linked article mentions, people would use AppleScript Studio because they are familiar with AppleScript, and can now, at their own pace, add new knowledge. They can add one small problem at a time, and learn to use AppKit and Foundation gradually, without having to familiarize themselves with the entire gargantuan complex system at once.

If you take one step back, you may as well ask the same question, once removed: Why do we use high-level languages that produce such inefficient code? Because most people don’t want to debug their push/pop stack management code and make sure the alignment is right before each call if the language can take care of this for most of their uses. And for the few cases where they need it, they can use inline assembler.

Both are the same problem and the same solution, merely at another level. Language bridges, garbage collection and other conveniences are not here to completely save you from having to learn the details of the computer’s workings. They are here so you can learn them later, out of order, and in smaller chunks. And they are also here to make life easier for those people that already know.

Helpful Xcode User Scripts

One of the more annoying tasks when writing Cocoa code is defining symbolic constants for all those keys when doing key-value coding. I’ve already posted my trick for getting auto-validated key-value-observing constants, but there are constants that aren’t accessors. Does lazy Uli have a trick for these as well?

xcode_user_scripts.jpg

Yes! Xcode has a really neat feature called “User scripts”. It takes the form of a little black scripture roll in the menu bar. If you open it, there is an “Edit User Scripts…” menu item. Choose it, and it shows a list of the scripts that come with Xcode, plus an edit field on the right where you can edit the current script.

The neat thing here is: These are just unix shell scripts. Notice the shebang at the top? That means you can specify every script interpreter, and you aren’t stuck with those terrible search-and-replace-with-side-effects-languages like bash or zsh. You could use Perl, or Ruby, or … heck, why not use PHP? Let’s do that, let’s solve our problem with constants in PHP. Click the “+” button and add a new script, change its name and give it a nice keyboard shortcut (I chose Cmd-Ctrl-K, K as in Konstant – C was already taken). Then paste in the folowing script:

#!/usr/bin/php
<?php
$fd = fopen( "php://stdin", "r" ) ;
$the_ident = fgets($fd) ;
echo "NSString*\t$the_ident = @\"$the_ident\"; \n";
?>

Make sure the “Input” popup is set to “Selection”, and the “Output” is set to “Place on Clipboard”. Now, whenever you need a new string constant as a dictionary key in Cocoa, you can just write the constant’s symbolic name

MyAppShouldOpenUntitledWindowPrefsKey

select it by double-clicking, hit Cmd-Ctrl-K, and then paste a finished declaration for it at the top of your source file:

NSString*   MyShouldOpenUntitledDocPrefsKey = @"MyShouldOpenUntitledDocPrefsKey";

Of course that’s just one of the neat macro things you can do. Since most scripting languages these days support regular expressions, you can do things like turn detect string literals on a line and generate a .strings file entry from it (or vice versa), put brackets and angle brackets around the selected expression (set the output to also be “Selection”), and do a multitude of other handy things.

Okay, you don’t really have to write code for putting brackets around certain expressions. Just look in the Edit -> Insert Text Macro -> C and Edit -> Insert Text Macro -> Objective-C submenus. You can use the Preferences window’s Key Bindings page to specify keyboard shortcuts (I chose Cmd-Ctrl-9, the key where my UK keyboard has the opening bracket, for Parenthesize Expression and Cmd-Ctrl-[ for Bracket Expression).

Of course, you can also put scripts in this menu that talk to the command line tool for your version control system of choice. For example, if you’re as addicted to GUI clients as I am, you’ll want the following script:

#!/bin/bash
# Find current document's repository root and cd to it:
MYPATH=`osascript -e "tell application \"Xcode\" to (path of document 1)"`
while [[ -n "$MYPATH" && "$MYPATH" != "/" && ! -e "$MYPATH/.git" ]]
do
	MYPATH=`dirname "$MYPATH"`
done
cd "$MYPATH"
if [[ -n "$MYPATH" && "$MYPATH" != "/" ]]
then
	# Now do our magic!
	open -a GitX.app "$MYPATH"
fi

This opens the current Xcode file’s Git repository in GitX so you can get yourself some hot merging and staging goodness. You can write a lot of code following this principle. For example, here is a script that does a git push on the project folder in a Terminal window, so you can actually type something into the password prompt:

#!/bin/bash
# Find current document's repository root and cd to it:
MYPATH=`osascript -e 'tell application "Xcode" to (path of document 1)'`
while [[ -n "$MYPATH" && "$MYPATH" != "/" && ! -e "$MYPATH/.git" ]]
do
 MYPATH=`dirname "$MYPATH"`
done

cd "$MYPATH" if [[ -n "$MYPATH" && "$MYPATH" != "/" ]] then # Now do our magic! IGNORE=`osascript -e "tell application \"Terminal\" to do script \"cd \" & quote & \"${MYPATH}\" & quote & \"; git push\""` fi

Any other suggestions for other useful scripts for coding that one may want to put in this menu?

Inference vs. Knowledge

I’ve blogged before about Sensible defaults and Anticipating User’s Needs. One suspicion that the feedback I received to this article raised in me was that people are very unclear about when inferring user intention is good, and when it gets in the way. Of course, this is not easy, and thus there’s no clear-cut answer, but if you’re aware of what you are doing, you can find the right way.

Distinguish Inference from Knowledge

Just like when designing any other algorithm, there are two extremes: On one hand, you may actually know what the user is trying to do. E.g. the user chooses the Quit menu item, and everything has already been saved: You know that the user wants your app to go away. It’s straightforward to implement.

On the other hand, there are also cases where you do not know what the user wants to do. E.g. the user has chosen Quit, but has unsaved changes. Does the user want to discard all changes made? Or did the user forget to save?

What can we do in the second case? Well, for one, we can apply a heuristic. We can assume that the user doesn’t want to lose data, and just save implicitly and then quit. Any user that actually didn’t want to apply the changes she did would simply be screwed. We could assume that the user knows what she’s doing and just quit and lose all unsaved changes. But everyone makes a mistake, and computers should be forgiving. No action the user initiates should be an irreversible mistake. Heck, even my washing machine lets me pause it and add a few more socks I found behind the couch. Why shouldn’t my Mac?

Still, both are options we have. There’s also the third option that we have: Put a fat stinkin’ dialog in the user’s face. This is the equivalent of grabbing someone about to leave a store by the collar and asking him: HAVE YOU PAID YET? This may sometimes be necessary, but generally you want to be nice to your user, you don’t want to halt them in the middle of their work. Ideally, you’d just quietly do the right thing.

The thing to keep in mind here is that you simply do not know what the user intended to do. Even worse: although the user explicitly said Quit, you do not know whether you should do that. This is neither bad or good, but it is an important thing to keep in mind when you design your program: How certain are you, that what your app is doing now is what the user wants?

If you are very sure, go ahead, do it. But what if you’re not so sure? The first rule should be: Do No Harm. The developer is given care of the user’s valuable data, her work, so he should not damage it. Take our quit example from above: In most applications today, you should not just quit if there are unsaved changes: Not saving would lose whatever changes the user just made, saving could damage the previous state of the data by applying changes that were never intended to be saved.

So, should we ask?

What if the user could just re-open the document and undo these damaging changes? In that case, just saving would actually be a much better choice. Nothing is lost, and the saved undo stack in the document lets us revert any damage.

So, you see, even in a common case, which is done so frequently in every application on your computer, you should actually be asking: What do I know? How sure am I of this knowledge? Is there a heuristic that lets me do something implicitly, but doesn’t hurt if I get it wrong?

Ask the User, but Do Not Ask the User

Another thing that is often done wrong when applying heuristics, is how to handle the situation where you aren’t sure what to do. Yes, you need a decision from the user, but that does not mean you should ask. Every time you put up an alert, you interrupt the user in their work, and force them to read the alert text and make a decision. If you do this too often, the user will just get used to clicking one of the buttons, without reading. The one time they actually made a mistake, they’ll already reflexively have clicked that button and be screwed.

Or in other words: Every time you put up an alert panel, God kills a cute little anthropomorphic paperclip.

You have many options to get input from the user, an alert isn’t the only one. And by alert, I mean everything that is kind of modal, including the weird status messages with buttons iTunes shows at the top of the window in its LED display.

For example, if your application detects at startup that it was quit with a document open, should it ask the user to reopen? I say no. What should we do instead? Well, look at your application’s workflow and typical use, of course!

If your application is mainly for generating documents, like GarageBand, where you typically create a song or Podcast over a period of time, then export it to a more standard audio format and publish it in some way, the user will likely want to return to a document. In that case, just reopen what was open last.

If your application is mainly for editing documents, for working with many documents, or for polishing and revisiting various documents, you’ll want to provide a “recent items” list instead. You can just use the built-in system menu, or you can additionally bring up a welcome window whenever no documents are open, showing recent items, templates for new files and an “open” button, like it’s done in Keynote or Xcode.

And if your application is one of those single-window monsters, for managing sufficiently distinct sets of items in a central database, you can put a “recent items” section in your sidebar. The user gets the main window, and has quick and obvious access to their most recently used item, without you loading a potentially huge item the user is not that likely to use.

Yes, I’m really saying that not asking the user, not doing anything, is OK sometimes. Your app doesn’t know with enough certainty what to do. You don’t want it to annoy the user. However, if you can infer a reasonably common case, you can still design your application to support the user in that task by making sure that, at this moment, the controls to achieve this common task (e.g. grabbing the most recent file) are within easy reach.

Also, sometimes an action is so nonsensical that you can be sure the user was trying to do something else. Instead of just telling the user “No can do”, your app can infer what they might have wanted to do, and offer to do that instead. You’re putting up an alert anyway, so why not put something useful in it?

You are not the typical user

When evaluating how certain you are about the user’s intents, also keep in mind that you are someone involved in application development. The way you use and understand the application goes much deeper than that of your users. You may know more about kerning, anchored selections and grammar-checking algorithms, while the users of your text editor may know more about particle physics or elaborate stitching, or whatever topic they are writing about when they use your text editor. A novelist has different needs than someone who mainly writes correspondence, who has again different needs from someone writing a technical manual.

So, when you infer that “everybody hand-picks their photos off the camera”, keep in mind that that may not at all be true. Someone taking a large amount of photos on a holiday to Lucerne, Switzerland, will probably want to quickly empty the memory card of the camera by transferring all photos to their Mac, and then quickly head out again with a fresh card, to enjoy the place more. They will want to just plug it in and have it import all while they take a shower.

On the other hand, a photographer on a scheduled outdoor shoot may be looking over each image anyway, to see whether he got the coverage he wanted, or whether he has to keep going to get the right picture because of a pedestrian in the background who was picking his nose at just the wrong moment, or a smudgy fingerprint on the lens that didn’t show up on the small camera screen.

So, how do I find out whether I’m right? Although there is no patented recipe, there are simple checks you can perform right away: Get a second opinion. Even if you just talk to a colleague, chances are that they use the app differently, and will spot an additional flaw in your thinking. You can give a test build to a friend and use them as your guinea pig. Ask your favorite user that e-mailed you with a “thanks for coding this” letter, how they would achieve a task that involves your new inference. Whatever. Of course, none of these people constitute a representative sample, but at least you’ll get additional data points to ponder.

And if you’re facing a big decision, you can always try more formal usability tests. But every little bit helps you gain experience, make better decisions, and discover those novel use cases you never considered.

But isn’t this inconsistent?

So you’ve tested something on your users and found that the system’s standard behavior doesn’t work. You’ve found a different solution, but now you’re wondering about consistency: everyone else on the Mac does it one way. Should you implement things differently?

The first thing you have to ask yourself is: What if a user forgets my app behaves differently? If they’ll lose data if they mix up the way your app and other apps they use work, you need to work harder. If it’s harmless … ? Well, you’ve done research to back it up, right? Tested it on a few friends, maybe even done a public beta? If you have a good reason and research to support your point that this behavior is better, then do it.

The number of beings doing something doesn’t mean it’s the best thing to do. Hey, there’s millions of flies eating doggy poo, still we humans don’t eat it…

Safe key-value-coding

[Screenshot of the warning in action in Xcode]

Daniel Kennett recently posed the question on Twitter how many of us were defining symbolic constants for use with Key-Value-Coding and Key-Value-Observing. After all, string literals are bad, because they don’t get checked by the compiler, so any typo in them goes unnoticed until you realize your key-value-observer method is not called, or you’re getting back nil where a property really contains a value.

That immediately sent me musing that it would be nice to have something like @selector() for specifying properties as NSStrings. The nice part about @selector() is that, given you’ve turned on the Undeclared Selector warning (-Wundeclared-selector), it will complain if given any selector that the compiler doesn’t know about yet. Which is usually the case if you make a typo.

Five hours later, the idea suddenly came to me: A property’s getter is a selector! And @selector() already does the checking and presents an error message. And one can use NSStringFromSelector() to generate an NSString from any selector. Now, those two are a little wordy, but you can condense that into a neat little macro:

#define PROPERTY(propName)    NSStringFromSelector(@selector(propName))

Admitted, this burns a few additional cycles because it turns a string constant into a function call, but NSStringFromSelector() can probably take an existing string constant from inside the SEL data structure, and you can always take it out of your release builds by writing:

#if DEBUG
#define PROPERTY(propName)    NSStringFromSelector(@selector(propName))
#else
#define PROPERTY(propName)    @#propName
#endif

This turns your property name into the string constant we all know and love in release builds, but does the checking in your debug builds (if you’ve set up your debug builds with a -DDEBUG=1 flag like many people do).

The advantage of this is that you get checked selectors, even when doing key-value-coding and key-value-observing, without any performance impact on your users. If performance is a problem, you can even only use the checked version of PROPERTY() in a special ‘tests’ build of your app. But of course then you can still find yourself flummoxed at a missing KVO notification until you do that special build and it complains.

I’ve added this code to my UKHelperMacros collection of macros, which is available on my UliKit repository on Github.

PS – Thanks to Rob Rix for reminding me of the existence of the # operator, and Jens Ayton for looking up the warning name just when I started wondering why I was getting the warning in one project, but not the other.

Drawing off-screen in Cocoa

In general, drawing in Cocoa always happens in an NSView‘s -drawRect: method on the main thread. The OS calls that whenever you’re supposed to draw anything, and if you want to redraw, you use -setNeedsDisplay: to ask the OS to call you back, and it will in turn call -drawRect:.

But sometimes, you just want to draw on a secondary thread, or you want to draw something for later use that shouldn’t show up in the view right now. The approach mentioned above seems awfully limited, doesn’t it? Of course there are other ways to do that.

A very easy way is to just take an NSImage, create it in your helper thread or threaded NSOperation, call -lockFocus on it, draw your stuff, call -unlockFocus and then send the finished image back off to your main thread using -performSelectorOnMainThread:withObject:waitUntilDone:. Note though, that doing a -lockFocus on an NSImage pretty much deletes and recreates the image contents, along with a Graphics Context needed to draw into the image, so if you plan to lockFocus/unlockFocus a lot, this will be fairly slow. In this case, you might be better off creating an NSBitmapImageRep directly and drawing into that, or even creating a CGBitmapGraphicsContext, doing your drawing in there, and only creating an NSImage from that once you’re finished.

Since you decide what to do with the NSImage once you’ve created it, this is a decent way to cache drawing that will need to be displayed later, or to pre-render more detailed versions of tiles of an image in the background to allow for more detail when zooming. It is also a way to speed up drawing of complex stuff. The CPU and GPU are fast enough to blast a full-screen pixel buffer to the screen at 50fps or more, but actually doing anti-aliased rendering of bezier paths or laying out text at this rate might be taxing the machine a bit. It also means all your drawing resources are together on your secondary thread, completely disconnected from the main thread. So it’s unlikely your thread has to wait for someone on the main thread to finish drawing, unnecessarily slowing things down.

If you really, urgently need to draw now, and need to do it on another thread (e.g. for video playback), you’ll need to do the threaded NSView drawing thing: Call -lockFocusIfCanDraw on the view, do your drawing, being careful that all your state has thread-safety locks or is immutable, call -flushGraphics on the current context and then -unlockFocus again. This is a bit dangerous due to all the thread synchronization points, though, and doesn’t work all the way back across system releases, so don’t do that if you can avoid it. If you want to learn more, see Apple’s thread-safety documentation.

Porting to the Macintosh

It comes up a lot on the mailing lists, so I thought I’d write a little piece on the best approach to port an application from another platform (like Windows or a Linux) to the Macintosh. I won’t go into much detail, but outline the general way and the most common pitfalls.

Do not use Carbon or Cocoa-Java

Apple has, for historical and political reasons, provided several different programming APIs. One of them is Carbon, which is a C-based API that many cross-platform developers want to use because it’s more like MFC and other frameworks they already know. At this year’s Worldwide Developers’ Conference (WWDC) a long-running fight inside Apple finally came to a close, and Apple effectively announced they were killing Carbon. There is still some old documentation up on Apple’s developer web site that says otherwise, but don’t let that fool you.

If you are just getting started programming the Mac, use Cocoa to write your end-user application with a graphical user interface. A few of Carbon’s prettiest cherries have been “rescued”, but look for a Cocoa solution first. In particular, any GUI code written in Carbon (control manager, HIToolbox) is not a good investment of your time at this point.

There are also a number of bridges that allow you to use Cocoa with other languages. They’re a great technology, but most of them are fairly new, and you will face issues. Also, since they map Cocoa/Objective C concepts to another language, there will always be something lost in the translation. You will have to know how Objective C does things to understand these oddities. So why not go for Objective C in the first place, where Apple spends its main effort? All the documentation is for Objective C, too.

Don’t even try to use the Cocoa-Java bridge. Apple has already made clear it will see no more development.

You can use C++ with Cocoa

Many people think they will have to rewrite their application in Objective C to make it use Cocoa. That’s not true. Apple has taken great care to make it possible to mix Objective C and C++ in a project. The key here is the “Objective C++ compiler”, which is part of Xcode. You will still have to write the Mac-specific parts in Objective C, but the rest of your application can stay in C++ and can be easily shared with your Windows or Linux developers.

Don’t be afraid of Objective C, Objective C is essentially C: It has a few simple extensions to the language, which are quickly learned. These extensions may seem like a fancy way of duplicating C++ just for the heck of it, but actually, they’re completely different. Objective C essentially is a very elegant and simple way of wrapping the features of COM or CORBA, Qt’s preprocessor, and many other neat things that are done separately on many other platforms. Moreover, the Cocoa frameworks have been designed with Objective C’s particular strengths and weaknesses in mind. Porting Cocoa to C++ would result in such an ugly mess of nested template code you wouldn’t want to do it.

There is no MFC on the Mac

If you’ve never before ported an application to another platform (and I don’t count Windows CE as a different platform than desktop Win32), don’t think you can just look at each function and map it to “the Mac equivalent”. Each platform has been designed at a different time, and thus incorporated the currently accepted programming practices. To create a usable application, you will have to do things the way they are intended to be done on a particular platform. For the Mac, this means making sure your application is split up into a model-, a view- and a controller-layer, according to the MVC design pattern. This is not a Mac-ism: It is a standard design pattern listed in the GOF book, and commonly accepted as the best way to structure a cross-platform application.

If you find that something seems impossibly hard to do in Cocoa, chances are that you’re doing something that you’re either not supposed to be doing, or that you are supposed to be doing in a completely different way. The benefit of this is that you will find yourself being boosted by the framework in ways you didn’t think possible, instead of finding yourself fighting it every step of the way.

Cross-platform frameworks

There are frameworks that have been designed to sit on top of a platform’s native frameworks and hide away the details, for example Qt, Quaqua or wxWidgets. In short: If you aren’t porting a game, where all user interface is custom and you’re full screen without a menu bar anyway, don’t do it. Most of these frameworks don’t really behave like Mac users expect them to. Menus look subtly wrong, don’t scroll and don’t indicate overflows correctly. Keyboard shortcuts don’t work as expected. Pushbuttons are used with the wrong style, disabled icons look black-and-white instead of faded out…

The long story: There are ways to make them work, but in the end, you can’t really share much code regarding UI behaviour, so you might as well go fully native on each platform. Most cross-platform toolkits get the look and the basic behaviour right, but at some point fall into an uncanny valley where they frustrate Mac users. However, of course you can wrap the Mac’s drawing APIs to share code for some of your custom views and displays.

Resources for Mac programmers

I already mentioned Apple’s developer web site above, which contains a lot of resources. In particular, you can find documentation, sample code etc. there. A lot of this stuff gets automatically installed on your Mac when you install the Xcode tools (in /Developer/Examples you’ll get a lot of the sample code, though not all of it, and the documentation can be found in Xcode’s Help menu, and it will automatically download the newest version periodically).

There is a whole section on porting from other platforms on Appe’s developer web site. Just keep in mind that anything suggesting Carbon is probably outdated.

Apple also runs a bunch of mailing lists for developers. These are mainly a place to meet other developers, and are not an official support channel. Nonetheless, make sure you post on the right list: Many people post Cocoa questions on the Objective-C mailing list, which is mainly about the language itself and the language standard, and rarely the one you want to post on as a Mac developer.

Finally, if you find issues, use Apple’s bug reporter, also known as RADAR. You need a free “ADC Online” account, but that’s just so you don’t have to enter your info twice. You can use the same account in Apple’s store and iTunes, BTW. Do not post your bug reports to the mailing lists. You can ask if someone has found a workaround, but the mailing lists aren’t an official bug report channel, and unless you bother filing a bug, Apple will just think you’re venting and it’s not important enough, and will focus on the bugs somebody actually filed and thus indicated they matter to them.

Custom Elements on WebKit Pages

Recently, I wanted to create a simple HTML editor. basically, I just wanted to WYSIWYG-edit styled text, and maybe insert a few images. But, of course there was one reason I could not use one of the existing HTML editors:

I needed to be able to insert special placeholder items. Little boxes, that could be double clicked for editing, and would otherwise just be part of the text like a regular character. In the final output, these would expand to special commands in a server-side scripting language, but I didn’t want to see them in the editor of course.

Luckily, after a bunch of code contributions and bug reports by Karelia, makers of SandVox, and then Mail.app using WebKit for editing styled e-mails, WebKit supports in-line editing. It is quite easy, actually: You just call [myWebView setEditable: YES] and give the WebView an empty HTML document. That is all you need to have a styled edit field from which you can get HTML and to which you can assign HTML.

Apple’s website also documents how to load HTML into the WebView, and how to get it back out. Loading is trivial using [[myWebView mainFrame] loadHTMLString: @"<html><body></body></html>"], and of course you can insert your HTML text in between these two tags. Writing them back out is slightly more complicated: What you do is get to the DOMDocument and then the documentElement from the mainFrame, then grab the element named @"body" out of that, and then you can typecast that to a DOMHTMLElement to obtain its innerHTML, which is a string containing the HTML for your styled text. If you want the full document and not just edit HTML fragments, you can simply take the document element’s outerHTML.

That was all straightforward so far, once I’d grown used to WebKit’s terminology. Now, how to manage the placeholders? Well, first, you will have to create a new WebKit plug-in project from the Standard Apple plug-ins category. This gives you a simple NSView, which you can associate with a MIME type by editing its Info.plist. Set up this project, so that it is built with your application project, and make sure you have a Copy Files build phase that copies it into a PlugIns folder in your application’s bundle.

You should now be able to specify an embed tag in your HTML source code with the type attribute set to your plugin’s MIME type, and WebKit will automatically load your plug-in and place it in this spot. However, you will either have to manually specify width and height attributes on the embed tag, or your plug-in will have to calculate the sizes, and use the arguments dictionary it gets passed on creation to add to them to the embed tag in code by manipulating the DOM tree through the DOMElement in WebPlugInContainingElementKey in the arguments dictionary. Since this key already refers to our embed tag, this is as simple as using the -setAttribute:value: call on this object, and using +stringWithFormat: to convert our sizes into strings.

What I learned from this? Once you know that there is no way to load a plug-in directly from inside your application, it is fairly straightforward to add your own objects to a WebView. Sadly, you always only know that after…

Cocoa Text System everywhere…

Sometimes, you need to draw text with more control than an NSTextField or NSTextView will let you do, and sometimes you need better performance than the NSStringDrawing category will provide. And maybe you need to draw text into a CGContext or even inside a Carbon application.

You may be thinking about CoreText right now, and how unfortunate it is that you still have to maintain compatibility with Mac OS X 10.4 “Tiger”, but there’s an easier way:

The Cocoa Text System

Just use the Cocoa Text System. The Cocoa Text System is a group of classes that NSTextView, NSTextField and NSStringDrawing use to actually draw strings. Now, if you look at Apple’s docs, you’ll first be frightened by how complex this whole system seems to be: there are NSLayoutManagers, NSTextStorages, NSTextContainers, NSGlyphGenerators, NSTypesetters… but don’t fear, it’s much easier than it looks.

Apple actually provides a great introduction in the Drawing Text with NSLayoutManager entry of the Drawing Strings Task Documentation.

If you read that, you’ll see that you actually only need to deal with three of these classes to draw any styled Unicode string wrapped to a text box: NSLayoutManager is kind of the main controller. The string to be drawn and its attributes are stored in an NSTextStorage, and the extents of the area to draw into is specified by the NSTextContainer. What’s more, once you’ve created these objects, you can cache them, and thus speed up repeated drawing of the same string significantly.

You create these objects using +alloc/-init as usual, then tell the layout manager to take ownership of the text container, and the text storage to take ownership of the layout manager. Here’s essentially Apple’s example:

NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:@"This is the text string."];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSTextContainer *textContainer = [[NSTextContainer alloc] init];
[layoutManager addTextContainer:textContainer];
[textContainer release];
[textStorage addLayoutManager:layoutManager];
[layoutManager release];

// Use the objects.

[textStorage release];

To actually draw this example string, you simply specify the size of the area to draw in, then ask the layout manager for the range of glyphs to draw, and then tell it to draw those at whatever position you want:

[textContainer setContainerSize: rect.size];
NSRange glyphRange = [layoutManager glyphRangeForTextContainer: textContainer];
[layoutManager drawGlyphsForGlyphRange: glyphRange atPoint: rect.origin];

Pretty simple, isn’t it? Two things to watch out for here: Whenever you change the size of the text container, the text needs to be re-wrapped (“re-layouted”), which is a sort of expensive operation that can be sped up by caching. Second, to actually trigger such a re-layout, you call -glyphRangeForTextContainer:.

For drawing styles and images, you simply take advantage of the fact that the NSTextStorage is actually a subclass of NSMutableAttributedString. So, it’s trivial to assign styles, fonts, colors and add text attachments.

Measuring Text

For example, if you want to measure how much space text will use, set the text container to have the height or width of the fixed side, and set the other side of the rect to some huge value, like FLT_MAX. Then, you call -glyphRangeForTextContainer: to make sure the text has been layouted, and then call -usedRectForTextContainer: to get the actual dimensions of the text:

[textContainer setContainerSize: NSMakeSize([self bounds].size.width, FLT_MAX)];
(NSRange) [layoutManager glyphRangeForTextContainer: textContainer]; // Cause re-layout.
NSRect neededBox = [layoutManager usedRectForTextContainer: textContainer];

The Cocoa Text System in Quartz or Carbon

Carbon uses the straight Quartz APIs. People who want to draw into OpenGL textures, PDF contexts and other custom locations often also use Quartz directly. So, what if you want to use the above text drawing methods in Quartz? You don’t have a an NSGraphicsContext, you only have a CGContext. What to do? Well, easy. Behind every NSGraphicsContext, there is a CGContext, and for every CGContext, you can create an NSGraphicsContext. So, if you have the CGContextRef in a variable named inContext, you can easily do:

[NSGraphicsContext saveGraphicsState];
NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithGraphicsPort: inContext flipped: true];
[NSGraphicsContext setCurrentContext: context];

// Do Cocoa drawing here.

[NSGraphicsContext restoreGraphicsState];

Of course, if you’re doing this in Carbon, take care to catch any NSExceptions and create an autorelease pool around calls like these, you wouldn’t want to leak Cocoa objects or have a Cocoa exception waltz through the Carbon system libraries.

The neat part about this is not only that the Cocoa Text System is much simpler than ATSUI, but also that the Cocoa Text system is very similar in design to CoreText. So, if you want to move to CoreText a couple releases from now, you’ll just have to swap out a few API calls, but the general workings will stay pretty much the same.

Using other people's classes

I have a bunch of open source classes on Github, so occasionally some kind people send me bug fixes. I’m grateful for that, and it’s one of the reasons why I make the code available. Some people also add new features, which is also very cool.

However, in many cases, they add new features by changing my class. And that always makes that little object-orientation alarm clock in my head go off: One of the reasons why subclasses are available in OOP is to let people use and modify library code without having to copy and paste or touch the original. If you change the class someone else writes, and that person decides that this change, for whatever reason, won’t be merged into the main code base, you will have to use FileMerge each time a new version is released, to apply your changes to the new version.

However, if you write a subclass that adds the features, you just drop in the updated base class, and the magic of inheritance will take care of doing the “merge” for you.

Mind you, I’m not complaining here. I’ve received some great submissions for some of my classes, from people like Todd Ransom, David Sinclair, David Rozga, and many others I’ve probably forgotten. Not to mention that, after I’ve stared at the same code for weeks, I just don’t see that missing [super dealloc] call anymore, and I’m grateful for the people who e-mail me and tell me. But I sometimes have plans for a certain class, and some changes some people suggest would collide with those. Or a certain change would break my or other users’ applications because it changes the behaviour of the class, and I have to turn it down.

If you write a subclass or a category that applies your changes, not only is your code completely self-contained and you don’t have to merge text files, it also makes it very easy for me to look at the code and see only your changes, without having to fire up diff myself, which may not be possible in an internet cafe anyway. And if I want to integrate it into the “official” version, I can easily copy and paste the stuff over. I’ll have to merge anyway, because I may also have made changes in the meantime.

Now, I won’t turn down a feature because it didn’t come as a subclass. I’m just saying that you could have a Shiny Happy Object-Oriented Feeling(tm), make it easy on yourself to get future updates until I get around to adding your modifications, and make it easier for me to check out your changes on the road.