The Road to Code: Leopard Detour
Volume Number: 23 (2007)
Issue Number: 11
Column Tag: Programming
The Road to Code: Leopard Detour
What's new for developers
in Leopard
by Dave Dribin
Short Detour
In this month's The Road to Code, we're going to be taking a short detour from the usual programming road. Instead of talking about Objective-C and object-oriented programming, I'm going to talk about Leopard. You may have heard about Apple's next generation operating system, Mac OS X 10.5, a.k.a Leopard. While much of the marketing buzz revolves around the new features available to the end-users, such as Time Machine, Spaces, and Cover Flow in The Finder, many improvements are in store for the developer, too. Since I still have not used Leopard extensively for development and there are far more changes than I can discuss in a single article, I'll be picking out some of the highlights that I've already encountered or am looking forward to using. While this article will be most useful for existing developers, you'll still learn a lot about developing for Mac OS X, even if you're not an old hat.
Development Tools
There are many improvements in the existing development tools, but there are also a couple of interesting new ones.
Xcode
Leopard comes with a new version of Xcode, Apple's integrated development environment (IDE), now up to Version 3.0. The first change you'll notice is that the main text editor has received an overhaul. The most immediate difference you'll encounter is that errors and warnings are now displayed inline as bubbles of text, as in Figure 1. While this is better than constantly keeping the build window open, or hovering over errors in the gutter to see the full message, it can also be a bit distracting. The bubbles shift lines of text down to fit themselves on screen, and I find this makes it a bit hard to see context around the error in question. For now, I'm keeping this option enabled, as it may grow on me over time.
Figure 1: Xcode error bubbles
The debugger has been better integrated, so that debugging doesn't require as much mental context switching. One of the best features is that the debugger can be invoked any time you run the application. There are no longer separate Build and Run and Build and Debug options. This is wonderful because often you are testing a program, only to realize that you'd like to set a breakpoint when something goes wrong. In the previous versions, you'd have to re-start the program under the debugger. Now, you can just set the breakpoint, and the debugger will automatically attach to your running application. In addition, there's no longer a separate debugger window, which helps keep you focused on the problem at hand.
Xcode 3.0 also provides the ability to refactor Objective-C code. Refactoring allows you to make your code more readable or simplifies its structure without changing the behavior. Other IDEs have had refactoring for a few years now, and it is a feature I am really excited about. Some examples of refactoring provided by Xcode are renaming variable names (including instance variables), renaming classes, extracting a block of code into a method, and the ability to move methods up and down in the inheritance hierarchy. While some of these can be done with search and replace, refactoring, in addition to being easier, is usually more accurate since it is not purely text based.
The long laundry list of changes does not stop there. Here's a taste of more new features:
Code folding and code focusing using a focus ribbon.
Code completion has been simplified with inline code completion.
Project snapshots allow you to experiment freely and revert code changes, if necessary. While I don't see this replacing a full-blown source code management (SCM) system, it is still nice to have.
A better Build Settings editor, including the ability to set architecture-specific settings.
The Research Assistant provides easy access to reference documentation, without taking your focus away from the code.
Adds the ability to have versioned Core Data models. This helps data migration as your model changes over time.
GUI access to SCM repositories.
For details, see the "Xcode 3.0 Feature Overview" document.
Interface Builder
Interface Builder also reaches Version 3.0 with significant updates. Interface Builder (IB) has a long history, going all the way back to NeXTSTEP (the .nib extension is short for NeXT Interface Builder), and was ripe for an update. The user interface has been completely updated for 3.0. Separate palettes for GUI controls have been replaced with the concept of a Library. All controls are now shown in a single list, as in Figure 2. While the Library still groups similar controls, you can also search for controls by name. The list dynamically updates to show only the matching controls.
Figure 2: Interface Builder Library window
IB also adds support for some new controls, but the one I am currently most excited about is support for NSToolbar. Toolbars have previously needed to be setup programmatically, which can be a bit of a chore. Now, you can add a toolbar to a window, add items to a toolbar, and hookup their actions all in IB.
The Inspector Window has been improved to support multiple selection. This a is big time saver, since you can now set properties of multiple controls all at once, rather than selecting each one individually. The best part, I think, is that you can select any set of controls, and only the common properties are shown.
My favorite update, though, is the ability for IB to automatically synchronize outlets and actions to header files. Gone are the days where you drag and drop changed header files from Xcode to IB to synchronize them. This single update alone will probably save you hours of frustration.
For a full list of changes, see "Interface Builder 3.0 Release Notes," but here's a quick list of other exciting changes:
Support for Core Animation.
Support for Tree Controller and Dictionary Controller.
Real-time animation to visualize springs and struts.
Interface Builder Plug-in model to replace IBPalette.
DTrace and Instruments
DTrace is a fantastic performance diagnostic and system tracing tool, originally developed by Sun Microsystems for their Solaris operating system. Sun released it as Open Source, and Apple has ported it to Mac OS X for Leopard. DTrace is a command line application that can be used not only to monitor system performance, but also as a debugging tool. For example, you can print out arguments of functions when they are called with very little overhead, and without recompiling. DTrace is extremely flexible and even has it's own scripting language called D, so you can use to write custom tracing scripts. And DTrace isn't just for user applications. You can use DTrace on the kernel and your own kernel extensions, too.
But the goodness doesn't stop there. Instruments is a new GUI performance monitoring tool, reminiscent of Garage Band, but for developers. You can add different "instruments" such as memory usage, CPU load, and object allocation, and you can see these measurements change over time. Under the hood, Instruments uses DTrace and it's essentially just a pretty face on top of libdtrace, the programmatic API for DTrace. This also means you can customize Instruments by writing your own instruments using D scripts.
I have not used DTrace or Instruments extensively but I am willing to bet that they will find a permanent home in my tool belt, along side Apple's already fantastic list of performance tools, such as Shark.
Objective C 2.0
The native language for Mac OS X applications, Objective-C, also gets a new major revision, giving us Objective-C 2.0. In Objective-C 2.0, we'll see fast enumeration, garbage collection, simplified property accessors, and enhancements to protocols.
Fast enumeration
Fast enumeration is combination of syntactic sugar and a speed increase. The old school way of looping through all objects of an NSArray is using an NSEnumerator, as follows:
NSArray * colors = [NSArray arrayWithObjects:
@"red", @"green", @"blue", nil];
NSEnumerator * e = [colors objectEnumerator];
NSString * color;
while (color = [e nextObject])
{
NSLog(@"Color: %@", color);
}
The new way to do this in Objective-C 2.0 is to use a special for loop syntax:
for (NSString * color in colors)
{
NSLog(@"Color: %@", color);
}
Not only is this easier to read, but it is apparently much more efficient than good ol' NSEnumerator. You can even add fast enumeration to your custom classes if you implement the NSFastEnumeration protocol.
Garbage Collection
One of the trickiest aspects of programming in Objective-C is dealing with dynamic memory management. Although reference counting is an improvement over malloc/free in C and new/delete in C++, it is still cumbersome and error prone. With Objective-C 2.0 comes garbage collection (GC) and the promise of making dynamic memory management painless. At a high level, this means you no longer have to send retain and release messages to objects to update their reference count. It also means you do not have to implement dealloc to free your instance variables. The garbage collector will find unused objects, affectionately known as garbage, and free them for you. It also simplifies your accessor methods. For example, instead of implementing setWidget: as follows:
- (void) setWidget: (Widget *) widget
{
if (_widget != widget)
{
[_widget release];
_widget = [widget retain];
}
}
You need to simply do an assignment:
- (void) setWidget: (Widget *) widget
{
_widget = widget;
}
The garbage collector also handles retain cycles properly, so you no longer have to deal with those specially. This is common in parent/child relationships and using delegates.
There is quite a bit more detail to garbage collection, especially if you are converting an existing code base, but this gives you a taste of what is available. It's also worth noting that Xcode 3.0 is itself a garbage collected application. I think this is a good sign for Apple to eat it's own dog food and it gives me a warm fuzzy that GC really is the way forward for new, Leopard-only applications. I think it will also quell the gut instinct of many who believe that GC impacts performance too much. As I usually say to people who worry about performance: profile it before blaming something. I'm sure we'll see more on this topic as Leopard gets thrown through the ringer in the months to come. Overall, I'm really excited to see get my hands dirty with GC, and I think it will make the learning curve for newcomers to Objective-C a little less steep. Oh, and in case you're wondering how all of your existing applications will work, garbage collection is disabled by default, so no worries.
Properties
Continuing the trend of making the programmer's life simpler is the introduction of properties. The concept of properties is not new to Objective-C and is the backbone of Key Value Coding (KVC), Key Value Observing (KVO), and Cocoa Bindings. After writing even a small amount of Objective-C code, you will find yourself writing a lot of boilerplate code for KVC-compliant getter and setter methods, affectionately know as accessors. As I showed above, implementing accessors has been simplified with garbage collection. Nevertheless, it's still a lot of brainless code to write. You have to implement two methods for each property, and if you can't use garbage collection in your application, it's even more brainless code. Objective-C 2.0 now has special syntax to work with properties.
New keywords are provided to simplify the declaration and implementation of properties. First, the declaration:
@interface Person : NSObject
{
NSString * _name;
}
@property(copy, readwrite) NSString * name;
@end
The @property line is similar to declaring name and setName: methods. It states that there is a property named name of type NSString *. The attributes given in the parenthesis customize the behavior of the property. In this case, copy means perform a copy in the setter, and readwrite means declare a getter and setter. A property can be readonly if there should be no setter method. There are other property declarations, too, so please see "The Objective-C 2.0 Programming Language" document for details.
On the implementation side, there is a new keyword to generate the method implementations for you:
@implementation Person
@synthesize name = _name;
@end
The @synthesize keyword implements the methods for property named name using the instance variable _name. Again, there are different ways to customize the property implementation so see the official manual for details.
The end result of using the property keywords is a lot less boilerplate code. But wait, there's more! Objective-C also provides a new dot syntax to simplify property access. Thus, instead of invoking the accessors methods as follows:
Person * person = ...;
NSLog(@"Name: %@", [person name]);
[person setName: @"Steve Jobs"];
You can use the dot syntax:
Person * person = ...;
NSLog(@"Name: %@", person.name);
person.name = @"Steve Jobs";
Protocols
The last feature of Objective-C 2.0 I'm going to introduce is an enhancement to formal protocols. Protocols define a set a methods that implementing classes must implement. Now methods can be defined as optional using the new @optional keyword:
@protocol MyProtocol
- (void) requiredMethod;
@optional
- (void) anOptionalMethod;
@end
Since optional methods are often seen in informal protocols, such as delegates, I think this feature will get used a lot. The benefit to using a protocol with optional methods over an informal protocol as that it makes your code more explicit and readable. It also improves the runtime metadata about an implementing class. For example, at runtime you can check to see if an object conforms to a formal protocol using conformsToProtocol:, but not an informal one.
Objective-C Runtime
The features listed above are for the Objective-C language syntax, but the runtime underpinnings also get an update. Mostly, this is transparent, but if you do any low-level hacking, you'll want to read up on the new runtime API. For example, class posing has been deprecated, so you'll need to find another way to accomplish what you want.
Much of the updates are for the new 64-bit implementation of the runtime. Because they didn't have to worry about keeping backward compatibility, some of the changes could be more extensive. Some of the improvements are better performance, support for non-fragile instance variables, and zero-cost C++ compatible exceptions. Be aware, though, that some features that are only deprecated in the 32-bit implementation are removed completely from the 64-bit implementation, such as class posing. See "Objective-C Runtime Release Notes for Mac OS X v10.5" for full details.
New and Improved APIs
The tools and language are not the only area to see drastic improvements. There are new and improved APIs to go along with those changes.
Core Animation
Core Animation is one of those revolutionary APIs that will probably change the way nearly all Mac OS X applications look and behave. Core Animation takes the power of the graphics card and unleashes it to the masses. Typically, you would have to really dig deep into OpenGL to fully utilize this power, but Core Animation makes it much easier by providing an API for fluid animation, 2D rendering, and 3D projections.
Core Animation itself is a lower-level API, but the Cocoa Application framework provides direct support for it. At the simplest level, some properties of an NSView and NSWindow are now animatable. This means that the new value does not get set immediately, but takes place over time. For example, if you set the frame of a view like this, the frame gets updated right away:
[aView setFrame: newFrame];
If, instead, you use the animator proxy to set the frame, the frame will animate to the new value over time:
[[aView animator] setFrame: newFrame];
Besides the frame, other animatable properties include the alpha value, rotation, and background Core Image filters.
If you want to fully utilize the power of Core Animation, you'll need to dig deeper into the lower-level API and work with layers. Layers are similar to views, in that they contain drawable content at a specific geometry, but they are much more lightweight. For example, it's possible to have hundreds of layers being rendered at once. Layers can be transformed, rotated, and zipped around using animations. Unfortunately, this is too large of a large topic to provide many details here. I suggest you read the "Core Animation Programming Guide" and look at the sample code for more information.
Cocoa Application Framework
The Cocoa Application Framework, affectionately known as AppKit gets a nice update in Leopard. AppKit is now 64-bit capable, meaning you can write 64-bit GUI applications to work with large amounts of data. In previous versions of Mac OS X, only Unix command line applications could be 64-bit. The nice thing is that there are not separate 32-bit and 64-bit versions of Leopard. 32- and 64-bit applications can be run side-by-side on the same machine, and you can even include both 32- and 64-bit versions of your binary in the same application bundle. Thus, you can ship a single binary to all your customers and not worry about what kind of machine they have.
There are quite a few new views and controls, too. Some of the standouts include:
NSCollectionView to provide an animatable list of views, like the pictures in iPhoto. The Library in Interface Builder is a nice example of NSCollectionView.
NSGradient, a class to easily create and display color gradients.
Native support for Heads Up Display (HUD) style windows. This is the dark gray, transparent window seen in many of the iLife applications, and it's available in Interface Builder.
Better Cocoa Bindings support with improvements to NSTreeController and NSArrayController and the addition of NSDictionaryController.
NSRuleEditor view to configure "rules" similar to Mail.
NSPredicateEditor view to create complex predicate expressions used in queries.
See the "Mac OS X v10.5 Developer Release Notes Cocoa Application Framework" document for all the changes to AppKit in Leopard.
Quartz Composer
Developers can now make their own Quartz Composer patches by subclassing QCPlugIn. This opens up the door for third party patches to make Quartz Composer even cooler than it already is. I am really looking forward to seeing what developers come up with, and how this is used inside of applications.
See the "Quartz Composer Custom Patch Programming Guide" for the full details on creating custom patches.
Other APIs
Other new and improved APIs and features include:
FSEvents to monitor file system updates.
Core Data 2.0, which includes support for versioning of managed object models and migration of data from one version to another.
Scripting Bridge to seamlessly interact with scriptable applications. For example, to get the current track in iTunes would look like:
NSString * currentTrackName = [[iTunes currentTrack] name];
The Calendar Store framework to provide access to data from the iCal application.
Updates to the Instant Message framework to support injecting audio or video content into a running conference.
The Image Kit framework to support drawing of images and easier image manipulation.
The PubSub framework to support RSS and Atom.
Updates to QuickTime Kit to support audio and video capture.
And much, much more! See "What's New In Mac OS X" for the complete list.
Resolution Independence
LCD monitor technology is improving rapidly, cramming more and more pixels into an inch than ever before. Ultimately this means crisper images and text. Unfortunately, there is currently little OS and application support for these higher resolution monitors. If no scaling is done, then text becomes too small and unreadable. If the OS tries to scale the user interface, then graphics can look pixelated or show artifacts.
With Leopard, Apple is pushing developers to make their applications resolution independent. Resolution independent means that the graphics and text should look crisp and clear on all monitors, no matter their resolution. In practice this means updating your artwork so that it scales properly. You also need to update any custom drawing code to make sure it does not assume a specific screen resolution. You can test your application to see what it would look like at different resolutions using the Quartz Debug tool.
Apple is obviously preparing developers so it can start using these higher resolution monitors in their products at some point in the future. We don't know when this is, so it's better to start early and begin updating your applications when Leopard comes out. Consult the "Resolution Independence Guidelines" document for more information on this topic.
Other Languages
The final feature I'm going to highlight is the new support for scripting languages, such as Ruby and Python. It is now possible to write full-blown Cocoa applications using Ruby and Python instead of Objective-C. This has been possible on previous versions of Mac OS X by downloading third party bridge frameworks, but Apple is now including RubyCocoa and PyObjc as part of the standard installation. This means you no longer have to bundle these frameworks with your finished application. It also means that Xcode includes templates for Ruby- and Python-based applications out of the box. Finally, it means that Apple will be supporting any bugs and issues that crop up with these bridges.
To give you a small taste of what this means, here is a short example of subsclassng NSView in Ruby, taken from the DotView sample RubyCocoa application:
require 'osx/cocoa'
class DotView < OSX::NSView
ib_outlets :colorWell, :sizeSlider
def awakeFromNib
@color = OSX::NSColor.redColor
@radius = 10.0
@center = OSX::NSPoint.new(bounds.size.width / 2,
bounds.size.height / 2)
@colorWell.setColor(@color)
@sizeSlider.setFloatValue(@radius)
end
def drawRect (rect)
OSX::NSColor.whiteColor.set
OSX::NSRectFill(bounds)
dot_rect = OSX::NSRect.new(@center.x - @radius, @center.y - @radius,
2 * @radius, 2 * @radius)
@color.set
OSX::NSBezierPath.bezierPathWithOvalInRect(dot_rect).fill
end
def isOpaque
true
end
def mouseUp (event)
@center = convertPoint(event.locationInWindow, :fromView, nil)
setNeedsDisplay true
end
def setColor (sender)
@color = sender.color
setNeedsDisplay true
end
ib_action :setColor
def setRadius (sender)
@radius = sender.floatValue
setNeedsDisplay true
end
ib_action :setRadius
end
Apple is also making it easier for other Objective-C and Cocoa bridges by creating a new framework called Bridge Support.
Conclusion
Well, that's a whirlwind introduction to Leopard. The developer has a lot to look forward to, and I think it is a very exciting release. Next month, we'll be back to our regular scheduled programming: learning the basics of Objective-C and programming for Mac OS X.
Dave Dribin has been writing professional software for over eleven years. After five years programming embedded C in the telecom industry and a brief stint riding the Internet bubble, he decided to venture out on his own. Since 2001, he has been providing independent consulting services, and in 2006, he founded Bit Maki, Inc. Find out more at http://www.bitmaki.com/ and http://www.dribin.org/dave/.