Checking Mac OS X applications for memory leaks
[info]chanson
A developer on the comp.lang.objective-c newsgroup asked recently how to check his Cocoa application for memory leaks.

Here's a simple process for using the leaks(1) command-line tool to investigate leaks in your applciation.
  1. Add some code to your application to wait instead of exiting, such as an atexit(3) callback that just sleeps:

      while (1) sleep(60);

    This ensures that your application stays around after it has otherwise completley shut down.

  2. Launch your application with the MallocStackLogging environment variable set to 1. You can set this by inspecting the executable — not the target — for your application. (See the malloc(3) manpage for more details on the environment variables that you can use with it.)

  3. Launch your application from within Xcode, run through a series of actions in your application, and quit your application. It should now be paused in your atexit(3) callback.

  4. Run /usr/bin/leaks against your sleeping application by specifying your sleeping application's process ID as its argument.

This will give you a list of blocks that leaks(1) thinks have been leaked from your application, their contents, and — thanks to the MallocStackLogging environment variable — the stack trace at the point each leaked block was allocated!

You can even do post-processing on this output to do things like format the stack traces and automatically file bugs against your application. Heck, you could even have your application have a debugging mode that launches leaks(1) And the best part: This isn't specific to Cocoa. It will work for Cocoa, Carbon, and even Unix tools. Anything that uses the standard system malloc(3) can be checked this way.

Mac OS X Developer Mailing Lists
[info]chanson

I just figured I would take some time out for a public-service announcement.

If you're developing Mac OS X software, you should really be on the appropriate developer mailing lists. Apple hosts a number of mailing lists at lists.apple.com and hosts archives there too. The lists are managed with GNU Mailman and have its convenient subscription and administration interface.

In my opinion, the principal lists for application developers are:

carbon-dev Developing software with the Carbon framework.
cocoa-dev Developing software with the Cocoa framework.
java-dev Developing software for Mac OS X in Java.
webobjects-dev Developing web applications with WebObjects and EOF.
xcode-users Using the Xcode Tools suite for Mac OS X development.

There are also a whole lot of task- and technology-specific lists, including lists for developers implementing AppleScript support in applications, developers working with networking, developers creating device drivers, developers writing multithreaded applications, developers working with Xgrid...

Be sure to look through the list of lists to see what else you can take part in.


Xcode: Unit Testing Series
[info]chanson
I've written a little on the support for unit testing in Xcode, but there are a bunch more things I'd like to write about. Specifically, I'd like to describe how to both set up and debug tests for Objective-C Cocoa and C++ Carbon applications and frameworks.

Also, be sure to check out the Unit Testing Guide.

Here are the posts in the series so far:

Xcode: SDKs and Cross-Development
[info]chanson
Xcode includes a feature called SDKs, which allow you to select a specific Software Development Kit to build against. This lets you easily target a version of the operating system other than the one you're actively running, letting you target an older operating system while using the most advanced version of the Xcode tools.

SDKs have really come to the fore with Xcode 2.1 and support for Macs with Intel processors. To build universal binaries to run on these machines, you need to build against the "Mac OS X 10.4 (Universal)" SDK. But why?

An SDK is a collection of frameworks, headers, and libraries for a specific version of Mac OS X. When you build against it, it's as if you're building against that version of Mac OS X — frameworks, headers, and libraries. So when you're building against the Mac OS X 10.4 Universal SDK, you're actually building against an SDK that includes universal versions of the 10.4 frameworks.

You can set the SDK to use on a per-project basis in the General pane of Xcode's project inspector, or you can set the SDK on a per-target basis in the properties for that target's configurations. You can even, if you're willing to enter a property yourself, specify which SDK to use on a per-architecture basis. This is all handled by the SDKROOT property; the value you specify for it is the path to the SDK package in /Developer/SDKs you wish to use. If you want to specify your SDK on a per-architecture basis, you can instead specify SDKROOT_ppc and SDKROOT_i386 properties.

Also handy is the Mac OS X Deployment Target property. Just like the SDK, you can set this either on the project or on a per-target basis. For its value, choose the earliest version of Mac OS X you wish to run on. So you can build against the Mac OS X 10.4 Universal SDK and, when running on Tiger, take advantage of APIs that are new in Tiger, but still be able to run on Mac OS 10.3.9.

This works because the Mac OS X Deployment Target property enables weak linking behavior. This means that you can build and link your application against a library provided with Mac OS X 10.4; when you run against the 10.3 version of that library, any new APIs defined in 10.4 will simply be NULL. This does mean that your own application will have to be careful not to call any 10.4 APIs on 10.3, but if it is careful it will be able to run.

The Xcode 2.1 User Guide has a lot more great information on this topic, in its section on Using Cross-Development in Xcode.

Xcode: Unit Testing
[info]chanson
Xcode 2.1 introduced integrated unit testing to the Xcode IDE. Xcode includes two unit testing frameworks, target templates for setting up test bundle targets, and infrastructure for running unit tests every time you build your project and reporting their results in the Build Results window just like compilers and linkers do.

With Xcode unit testing, you group your test cases into test bundles which are built by separate targets. This means that you don't need to build two versions of your software — one with tests and one without tests — and can run your tests against the actual software you want to deliver.

Xcode 2.1 and later include OCUnit for unit testing of Objective-C Cocoa software, and it includes a new framework called CPlusTest for unit testing of C++ software. Using either you should be able to test C code with relative ease. Corresponding target templates are included for creating unit test bundles appropriate for Cocoa and Carbon applications and frameworks, and file templates are included for creating OCUnit and CPlusTest test case classes.

The test bundle target templates have a shell script build phase at the very end that invokes /Developer/Tools/RunUnitTests. RunUnitTests looks at the build settings it's passed via its environment and determines from that information how to run the tests in your test bundle.

If you're testing a framework, RunUnitTests will run the appropriate test rig and tell it to load and run the tests in your bundle. Since your test bundle should link against your framework, your framework will be loaded when the test rig loads your bundle.

If you're testing an application, you need to specify the application as the Test Host and Bundle Loader for your test bundle in its configuration's build settings. The Bundle Loader setting tells the linker to link your bundle against the application that's loading it as if the application were a framework, allowing you to refer to classes and other symbols within the application from your bundle without actually including them in the bundle. The Test Host setting tells RunUnitTests to launch the specified application and inject your test bundle into it in order to run its tests.

There's even support in RunUnitTests for invoking a test rig of your own, rather than the test rig for one of the supplied frameworks. You just need to specify the Test Rig build setting for your test bundle; this should be the path to a tool to run. It will be passed the path to your test bundle as its first argument, and if it needs to generate failure information it can just generate it in a gcc/compiler-like format on stderr:
FailingTest.c: 10: error: (1 == 0) failed
This will cause it to show up in the Build Results window as an error, just like a compiler or linker error. You can see the RunUnitTests manpage for more information on the environment in which your test rig will be run.

There's a great Unit Testing Guide on the Apple Developer Connection web site that has lots of information on getting started with Xcode unit testing. Check it out!

Don't assume thread safety.
[info]chanson
Is a random API thread-safe or callable from threads other than the main thread?

Think about it: It takes effort on the part of the creator to make an API thread-safe. You need to make sure it's properly managing access to any internal shared state, which means more work during design, more time during development, and more testing.

The upshot of this? You shouldn't assume, in the absence of general or specific documentation to the contrary, that any particular API is thread-safe. Period. I'm not talking about any particular platform or API here either — this applies everywhere. It's just one of those assumptions you shouldn't make. And it applies both when calling the API from multiple threads at once and when calling it from any thread other than the main thread.

The corollary is that you also can't assume that you can make an API thread-safe by surrounding it with locks. Just because you're ensuring your code is only ever invoking that API from one thread doesn't mean you're catching every invocation of it. Better to play it safe.

"Recent Documents" in Windows Forms
[info]chanson
Windows has long had support for a "Recent Documents" listing in its Start menu. Functionally this menu behaves the same as the Recent Documents folder in the Apple menu in both the traditional Mac OS and in Mac OS X.

On the Mac, management of this list is handled entirely by the operating system. The Finder and the standard Open and Save dialogs work together to ensure the list is always up to date.

On Windows, however, you have to do the work yourself. In the second part of his series on implementing document-based applications in C# with Windows Forms, Chris Sells describes how to do this:
In addition to seeing their files in the Explorer, users are accustomed to seeing their most recently accessed documents in the Start->Documents menu. If you want those files to be added to that list, you'll have to call the Win32 function SHAddToRecentDocs, exposed from shell32.dll. Unfortunately, there's no .NET wrapper for that function, so you'll have to use a bit of Win32 interop to gain access to it:
And then he shows us the code.

In the article, Sells also describes how to manipulate the Windows registry to ensure that your application will be bound to its document type, and to associate an icon with both documents and the application. Predictably, you have to do this in code. Yes, core Windows functionality like managing the recent documents list is not only left for every application developer to implement, the mechanism used to implement it isn't even natively supported by .NET.

Sells also goes on an irrelevant tangent about how easy it is to build an MDI application when you have a working SDI application. MDI is the abominable "many document windows inside a maximized parent application window so you can't work in more than one application at once" interface Microsoft has been trying to get developers to stop using for the past eight or nine years; it stands for "Multi-Document Interface." SDI stands for "Single-Document Interface" and presents a much more natural interface to users, where there's no giant "parent window" preventing them from working with multiple applications at once.

Predictably, creating an MDI application also involves writing a bunch of code. At least its interface is defined using the form designer, and not by writing even more code. But why would you even want to foist an MDI application on your users when it's easier to build a better SDI application?

Let me get this straight: This is the state of the art in Windows application development? And people think it's cost-effective to build enterprise applications using these tools? On Mac OS X using either Cocoa or Carbon the operating system manages recent items for you. It's trivial to associate a file extension with your application: You just declare it in your application's property list, and the operating system notices. It's trivial to associate an icon with your application, and with any of its documents: You just declare them in your application's property lists, and the operating system notices. And there's no MDI garbage to get in users' way as they work on ever-more-complex tasks using multiple tools at once.

With Cocoa on Mac OS X, you can accomplish more using less code. This is especially true with Panther and the introduction of NSController, but all of what I talk about above was our reality in early 1999 with Mac OS X Server 1.0.

Platform Futures
[info]chanson
On Windows, many developers seem to want to run as fast as possible away from Microsoft Visual C++ and embrace Microsoft's C# and .NET platform for new development. Most Windows developers that I've seen seem downright enthusiastic about these technologies. It's disconcerting; I'm not used to seeing Windows developers (or users) be enthusiastic about their platform.

On the Mac, many developers are trying to hold onto C++ and Carbon for as long as they can, even for new development. A new Mac developer on the Carbon list actually said he wished Apple had a C++ framework that used MFC-like "message maps" for Mac OS X-only Carbon development "to make it easier to build software fast!" (Paraphrased.) And Metrowerks is spending money & time building a next-generation C++ PowerPlant framework for Mac OS X-only Carbon development! And some developers keep on Apple's case to try and maintain feature parity between Carbon and Cocoa.

Fortunately, Apple isn't giving in to them as much as they might think. For instance, WebKit has a Carbon wrapper, but it's just a wrapper; WebView is really a Cocoa framework and if you want to extend it you're going to have to use Cocoa. The Cocoa Controller layer is only really possible to do with a rich dynamic runtime; it'll never make it to Carbon. You can only build screen savers using Cocoa and Objective-C. You can only build preference panes using Cocoa and Objective-C. Virtually all new applications coming out of Apple are built using Cocoa and Objective-C.

(Keynote, SoundTrack, LiveType, iCal, iPhoto, iSync, iChat AV, Safari... Final Cut and Logic don't count, since they ware originally developed for the traditional Mac OS and thus aren't new. Neither does Shake, since it was originally developed for Irix and X11 — though it wouldn't surprise me at all to see it rearchitected as a Cocoa application in the next couple of years.)

The future of development on Windows is C# and .NET. This has been clear since Microsoft first released .NET, and it's especially clear in light of the latest PDC and Longhorn.

The future of development on the Mac is Objective-C and Cocoa. This has been clear ever since Apple bought NeXT, and it's especially clear in light of the latest WWDC and Panther.

Deal with it.

Scoble Doesn't Get It, Part XII
[info]chanson
Scoble harshes on me for saying the poor quality of Quark's code and developers is the reason why they took two years to ship for Mac OS X.

He actually says this:
First, anyone who says that their customers write crappy code sure shouldn't be allowed anywhere within 50 yards of customers.

It's a good thing Quark isn't my customer! See, I don't work for Apple. I don't represent Apple in any way. I'm a third-party developer. I do high-end custom software development through my consulting firm. I also teach others to do software development. I, unlike Scoble, know a thing or two about software development.

Here's the deal. Carbon is a great tweak on the old Macintosh Toolbox programming interfaces. It was not a "break with the past" as Scoble says - it started as an updated version of the Toolbox that could be used to bring existing Mac applications to a modern operating system with preemptive multitasking and protected memory. Carbon has a bunch of additional great features too that let you create very nice Mac OS X applications that aren't limited by what could be done in Mac OS 8.6 in 1998, but at its heart it's just an extension and revision of what existed before. And here's the important point: This is the only way such a transition could be made for these applications. They could not be run natively on Mac OS X any other way.

Oh yeah, Carbon applications that stick to a subset of the API (essentially only using features available on Mac OS 9) will run on the classic Mac OS too, so you don't need to abandon those users to run on Mac OS X. I can run some Carbon applications on every release of the Mac OS from 8.1 through Panther, on hardware from a 6100/60 through a dual-2GHz G5. So Apple's not even forcing developers to make a break with existing customers.

If your existing Mac software is well-written, and you're dealing with a normal application (not a device driver, system extension, etc.) getting a first cut running under Carbon is actually pretty straightforward. In an application the size of QuarkXPress there might be a bit of tedious detail work to do — for instance, transforming all direct accesses to members of Toolbox structures into accessor function calls — but it's not difficult. It's only if your software is poorly written or the people doing the work aren't very good that this process takes a substantial amount of time.

All of the publicly-available evidence, in the forms of public posts by developers with "@quark.co.in" email addresses to public Macintosh development mailing lists, is that both cases are true: Their code is terrible, and the developers aren't very good. I wish I had better news, but I don't.

Oh, wait, I know. Silly me and my attitude. Apple should have crippled Mac OS X so QuarkXPress would continue to run natively. Or Apple should have poured cash into Quark starting in 1999 to ensure that QuarkXPress would be native when Mac OS X shipped (despite the fact that developers had access to prereleases for quite a long time and many applications including Adobe InDesign and Microsoft Office shipped relatively quickly). What's wrong with me for not realizing this?

Oh, and I should know better than to ever criticize anyone for doing shoddy work and blaming others for their failings. I should just keep my mouth shut and nod pleasantly while idiots peddle garbage. Right. Maybe I do have an attitude after all. I prefer to call it "taste."
Tags:

Cocoa versus Carbon graphics speed
[info]chanson
On the Cocoa-Dev mailing list, John Nairn asks why rectangle fills are so much slower in Cocoa than they are in Carbon. Essentially, he has a custom NSView which contains a large number of elements (100 to 100,000) that may need to be drawn. Each element responds to -stroke: to do its own drawing, which apparently consists of filling a rectangle.

Here's my answer to John, slightly edited compared to what I posted in response on the mailing list:

There are substantial differences in the graphics architectures between QuickDraw and CoreGraphics.

In QuickDraw, you're always working in pixel coordinates. In the worst case, your coordinates have to be translated from port to global coordinates, and then your rectangle can be filled.

In CoreGraphics, you're always working in an abstract "user space." Coordinates in user space are mapped to device space via the concatenation of two translation matrices; they're mapped from user space to ideal space (with 72 points per inch) by the current transformation matrix (CTM) and from ideal space to device space via another matrix. Right now, in CoreGraphics, when drawing to the screen ideal and device space are the same thing. But they don't have to be, and aren't when printing.

OK, so instead of one simple addition per coordinate for your rectangle, you have a matrix multiply. That costs a bit right there, but it gets you a lot of flexibility.

There's even more to filling a "simple" rectangle in CoreGraphics though. QuickDraw will fill your rectangle with a simple pattern. CoreGraphics patterns are much more complex — there's a lot more they can do. CoreGraphics cares about line joins and end caps and line patterns and mitre limits and a whole lot of other arcane bits. In QuickDraw, you're fundamentally just setting bits; in CoreGraphics, you aren't, you're creating path objects and manipulating them, which results in bits being set. You're working at a higher level of abstraction.

Essentially, an implementation of NSRectFill looks something like this:
  void NSRectFill(NSRect rect) {
    NSBezierPath *path = [NSBezierPath bezierPathWithRect:rect];
    [path fill];
  }
It's creating a path, filling it, and then tossing it out. That's expensive.

One way to speed up your code would be to create a real NSBezierPath for the rectangle, and keep the path itself around. You can then replace your NSRectFill(ptRect) with something like this:
  [cachedPath removeAllPoints];
  [cachedPath appendBezierPathWithRect:ptRect];
  [cachedPath fill];
Another thing you could do is keep a unit square path around, and then just scale & translate the coordinate system as necessary before filling your unit square path. That's what's happening behind the scenes anyway; you could "cut out the middleman" and only do the work you really need to do by going that route. I'm not sure whether or not that'd be faster, but it might since all you'd be doing is manipulating the CTM.

Another thing you should definitely do to speed up your code is only draw those portions of your view that actually need to be redrawn. Do an intersection test with the rectangle passed to your view's -drawRect: method, and only draw those that intersect with it. Also, be careful not to use -setNeedsDisplay: but rather -setNeedsDisplayInRect: to tell the AppKit that a view needs to be refreshed. That will let the AppKit determine the optimal rectangle to update; it won't try to update everything all the time. This would probably require that your elements keep track of their own radius, rather than asking the sender of -stroke:; either that, or the sender of -stroke: should also keep track of the current rectangle passed to -drawRect: and allow your elements to look at it to determine whether they need to be drawn.

I hope this gives you some idea as to why what you're doing has different performance characteristics with Cocoa/CoreGraphics and QuickDraw, and gives you some strategies for ways you can optimize your drawing.

CoreGraphics does a lot more than QuickDraw and is quite a nice architecture, but it's not without its costs.