My first exposure to Macintosh programming was with THINK’s Lightspeed Pascal in 1988. I was a graduate student at the University of Utah and the teaching assistant for the introduction programming course using Pascal. The student machines were Mac SEs running Macintosh System 2. Pascal provides a fairly encapsulated runtime environment to simplify its use in teaching programming, so it wasn’t really “Macintosh programming” although you could interact with the toolbox if desired.
Twenty years later, I find myself working at a digital content company and our content creation applications support both Windows and Mac OS X as a customer platform. While we largely rely on UI toolkits to isolate our applications from UI differences between platforms, we still need to build and debug code on Mac OS X. All of this work is done in Xcode. I was in a weird situation: I needed to know how to use Xcode, but I didn’t need to know how to program Mac native applications. I needed a book that would tell me about Xcode and how to accomplish typical developer tasks in it, but I didn’t need a book that would spend too much time on Objective C, Carbon APIs, Cocoa APIs and other Macintosh specific coding tasks. “Xcode 3 Unleashed” by Fritz Anderson is just the book I needed.
Because we use UI toolkits to insulate our applications from the details of the platform, we don’t often have to write platform specific code for our applications. This is a great time saver, but at the same time it does leave you relatively ignorant about the underlying platform API. I’ve read extensively on the Windows API, so when I encounter the need to program to that level its not a problem. For the Macintosh APIs, there are abundant online resources on Apple’s developer website that can be used as a reference. The first event-driven GUI framework I learned was the Amiga Intuition framework, followed by Windows 3.1, the X Window System (first version 10, then version 11), Win32, wxWidgets and Qt. Learning your first event-driven GUI framework is a big mental shift from the console oriented programming provided by traditional Pascal and C environments, but once you learn your first framework its easy to pick up another one. That makes it relatively easy to leverage your knowledge of Windows or other GUI frameworks when solving particular problems on the Macintosh APIs.
However, when it comes to development environments it isn’t so easy to translate knowledge of one development environment to another. When I first started using Visual C++ 6 in 1998, it was my first exposure to an integrated development environment. Before that I had been programming in a Unix environment mostly using emacs for editing, building and debugging. “M-x compile” and “M-x gdb” was my development environment integrated into emacs. It took a little while to become comfortable with using an IDE and I still installed a Windows version of emacs on the machine for the occasional editing of huge text files.
There was a bunch of functionality embedded with Visual C++ that was a bit jarring to me as a unix developer. I wasn’t familiar with “Wizards” and was initially skeptical of the value that they provided. Once I learned that they were generating boiler plate code and I understood the underlying APIs and frameworks (MFC, ATL, etc.) used by the boiler plate I recognized the value in having a Wizard generate the boiler plate. I still recommend that new programmers understand the generated boiler plate so that they can know when to leave it alone and when to change it to suit their needs. Over time as I learned the keyboard shortcuts for VC6 and became more familiar with the editor, debugger, project and workspace system I found I didn’t yearn for Makefiles anymore and I was much more productive in manipulating, exploring, editing and creating source code. I was more productive than I had ever been while using emacs and Makefiles.
I knew that Xcode was a GUI layer built on top of gcc for compiling and gdb for debugging. Mac OS X has unix sitting underneath it, so all my knowledge of unix would be helpful in manipulating files and navigating around the file system. I knew I could figure out low-level compiler or linker errors as long as I could see the command line supplied to the compiler or linker. That’s all fine and dandy in the abstract, but as they say, the devil is in the details. There were two main areas where I needed to know the details for Mac OS X: how GUI applications were packaged and deployed and how to navigate the Xcode GUI to perform the development tasks needed to create GUI applications for Mac OS X.
I had looked at a couple of other Xcode books and found them to be too chatty and spend too much time on topics I didn’t need to know in detail: Objective C, Carbon APIs, Cocoa APIs, AppleScript, and so-on. “Xcode 3 Unleashed” had just the right level of discourse and detail that I needed. I found the text to be concise and readable without digressing into irrelevant cocktail party style chat-chat that I found in other Xcode books. “Xcode 3 Unleashed” breaks down into two main parts: Part I: The Life Cycle of a Mac OS X Application (chapters 1-19) and Part II: Xcode Tasks (chapters 20-27) and Part III consisting of appendices. The chapters are as follows:
- Kicking the Tires
- Simple Workflow and Passive Debugging
- Simple Active Debugging
- Compilation: The Basics
- Starting a Cocoa Application
- A Cocoa Application: Views
- A Cocoa Application: Controllers
- Version Control
- Property Lists
- Libraries and Dependent Targets
- File Packages and Bundles
- Unit Testing
- Creating a Custom View
- Dynamic Libraries and Frameworks
- Documentation in Xcode
- Using the Data Modeling Tools
- Spotlight (or, how to Build a Plug-in)
- Finishing Touches
- Navigating an Xcode Project
- Xcode for
- More About Debugging
- Xcode and Speed
- A Legacy Project
- Shark and the CHUD Tools
- Closing Snippets
Part I: The Life Cycle of a Mac OS X Application
Chapter 1 introduces you to Xcode and its project assistants, similar to the wizards in Visual Studio. The chapter leads you through creating a command-line “Hello World!” style application. Along the way, the author is careful and consistent in his use of terminology so that you will understand the correct names for the elements being discussed. (For instance, I didn’t know that the triangles in Mac OS X that you click to reveal layers of a hierarchy are called “disclosure icons”.) When learning a new domain, it is important to understand the terminology so that when you discuss issues with other developers in that domain you’ll be talking in the same vocabulary. The book is also profusely illustrated with full-color screen shots of the interactions with the Xcode GUI. This becomes particularly helpful when the way to achieve a certain operation or relationship between items in the GUI is to drag items from one area of the GUI and drop them on another. These operations are illustrated clearly with annotated screen shots depicting the operations.
Chapter 2 introduces the problem of performing a linear regression on a set of data points. This problem is reused throughout the book as the context within which the different Xcode operations are explored. The chapter intentionally introduces some programming errors in the provided code so that the GUI for build errors can be demonstrated. Another intentional error causes an access violation when the program is run. This is used to demonstrate basic use of the debugging windows and the underlying gdb debugging console. Chapter 3 continues a discussion of the debugger illustrating how to set breakpoints and perform edit-and-continue style debugging.
Chapter 4 goes into more detail on compilation, linking and dynamic loading of libraries. It also explains the legacy subjects of prebinding and ZeroLink that you may encounter in documentation. I liked that just enough time is spent on these legacy subjects to explain what they are without going any further detail. Chapter 5 creates a Cocoa GUI around the console based linear regression program created earlier. It executes the linear regression console program as a separate process and uses it’s stdin and stdout for I/O. Because the GUI application is dependent on the console application, Chapter 5 also shows you how to create dependencies between projects and relationships between the outputs of the projects.
Chapter 6 introduces Interface Builder, the GUI designer for native Mac applications. This is similar to the forms designer in Visual Studio. Interface Builder includes mechanisms for controlling layout and sizing of controls as you would expect. Chapter 7 expands on chapter 6 by showing you how to add a controller to a view and provide bindings between the controller and your application objects. Although we don’t use interface builder at all in our applications, it was still useful to skim through these chapters as they had useful items embedded within them. Chapter 7 includes a discussion of application properties and how to set them. These end up in the application’s
Info.plist file and contain items that every application will want to set, even if you don’t use interface builder.
Chapter 8 discusses the version control features of Xcode. In our company, some developers have chosen to use SvnX to provide a GUI for subversion. I was comfortable with the command-line usage of subversion, but chapter 8 showed me how to integrate knowledge of subversion into Xcode so that creating new files in Xcode caused them to be added to subversion. Where I work, we tend to do most of our development work on Windows and deal with Mac problems afterwards, so we don’t often need to perform subversion operations directly from Xcode, but its still handy to have it configured if you need it.
Chapter 9 discusses property lists and their importance in Mac OS X applications. A useful nugget for me in this chapter was a discussion of the
plutil utility for converting property list files between binary and ascii XML forms. Chapter 10 covers static libraries and dependencies between build targets in depth. The linear regression code from earlier chapters is refactored into a static library and the console and GUI applications for linear regression are made dependent upon the static library target.
Chapter 11 describes file packages and bundles. These are shown in the Macintosh finder as a single item but are maintained on the file system as a directory with a specific organization and contents. The
Info.plist file is discussed in more detail in terms of how it relates to an application bundle. Chapter 12 introduces unit testing and the Cocoa unit testing framework using Objective C and refactoring. Xcode 3 is the first edition of Xcode to provide some refactoring support in the IDE. Unfortunately it only provides this support for Objective C applications and C/C++ applications still have no refactoring support. Chapter 13 covers creating a custom view using Interface Builder. You’ll need this if you’re writing native Mac applications with GUI needs that aren’t covered by the standard controls and views.
Chapter 14 explains the details of dynamic libraries and frameworks. This is an important discussion, even for applications that use GUI toolkits to isolate themselves from the details of the platform’s native GUI API. I found this chapter particularly interesting because it answered my questions about frameworks: what are they, why do they have the directory structure that they do, how are they used by the application loader in OS X and how do they interact with dynamic library loading.
Chapter 15 describes documentation in Xcode. This covers both the built-in documentation provided by Xcode that describes the Macintosh APIs and applications, but also how to generate documentation from you own source code. Many teams use a tool like doxygen to generate documentation from their source code. Xcode includes a tool called HeaderDoc that performs similar duties, but it isn’t as powerful as doxygen. Annotating source code with special comments becomes a bit tedious when you have to type those comments manually. Chapter 15 shows how to use AppleScript scripts to automate inserting these boiler plate comments and other editing tasks. Once you’ve generated documentation, the chapter shows you how to create a shell script target that automates the process of incorporating the generated documentation into Xcode’s documentation browser.
Chapter 16 describes the data persistance facilities introduced in Mac OS X 10.4. If you’re writing a native Macintosh application, it may be helpful to use the data modeling, persistance and UI support in OS X for your data sets. Chapter 17 explains how to build applications that target a specific version of Mac OS X, which may be different from the version of OS X on your development machine. This is important as developers often have their development machines on the latest version of the OS but need to compile applications that target earlier versions. Windows applications have similar mechanisms available to them through the Platform SDK. Chapter 17 also discusses universal binaries that let you target a combination of 32-bit, 64-bit and PowerPC and Intel architecture machines with a single executable.
Chapter 18 talks about how to extend the metadata system introduced in OS X 10.4 with a Spotlight plug-in. Writing such a plug-in lets you expand the metadata shown in the Finder for data files generated or consumed by your application. Chapter 19 covers some finishing touches you may want to put on your application. It explains how to provide localized resources to support internationalized applications. Of interest to most C/C++ programmers is a discussion of analyzing memory usage and finding memory leaks in applications.
That concludes the chapters for Part I, racking up an impressive 328 pages. For my needs, I read most of the chapters that explained OS X or Xcode concepts and skimmed the chapters that dealt with tools or facilities that only related to native Macintosh applications. I didn’t read every word of the Interface Builder discussions, but I did skim those chapters to find the sections that would still be relevant to what I needed to do in my own applications.
Part II: Xcode Tasks
Chapter 20 shows how to navigate the source code in a project. You’re shown how to navigate through the code in the editor window and through the project window. There’s also a discussion of the class browser and class modeler windows in Xcode. Of particular interest to me was a discussion of tailoring the window layout of Xcode. By default, Xcode opens each new window in its own top-level window. For me, this just creates a confusing plethora of top-level windows. This chapter showed me how to change that preference to a layout more similar to Visual Studio, the all-in-one layout. Some coworkers had tried changing this setting before in Xcode but were frustrated in their attempts because you can only change this setting when no Xcode projects are open. This was explained in the book, but it isn’t obvious at all when poking around Xcode.
Chapter 21 explains the Xcode build system in terms that will be familiar to users of make. While I am not necessarily a fan of make, it does get the job done and many people are familiar with it due to its longevity. (I think I first used make around 1984!) Understanding the Xcode build system, how its options are exposed in the Xcode GUI and how they ultimately relate to the command-lines that are executed to build your product is something that every developer of Macintosh applications needs to understand. This chapter also explains how to augment your build process with additional custom processing steps so that you can leverage Xcode to automate as much of your build as possible, minimizing the need for additional scripts.
Chapter 22 goes into more detail on the debugger. It describes some specific debugging techniques using parts of the debugger that haven’t been discussed previously, such as the call stack window. It explains how to display data in the gdb console window with specific formats (hexadecimal, octal, string, pointer, etc.) and how to augment the existing data formatters in Xcode with custom formatters for your own datatypes. You can add specific debugging commands to a breakpoint so that they’ll be executed when the breakpoint is hit. This is useful for printing out the relevant state at that particular breakpoint. You can also set conditions on breakpoints. All of this will be familiar to existing users of gdb, although Xcode adds some GUI for setting these options. Something new to existing gdb users is the “mini debugger”, a small floating window that hovers over your application allowing you to interact with the debugger without causing your application to lose the window focus.
Chapter 23 covers the topic of speeding up your builds. If you’ve used gcc before, you know that while its a nice compiler, its not exactly a speedy compiler. If you’re producing universal binaries, then be prepared to double or quadruple your build time for release builds at least. Xcode provides some ways to reduce build times through the use of precompiled headers and distributed builds. This chapter explains how to configure and use these options. Chapter 24 explains how to use the Organizer window to arrange and organize arbitrary files on your file system that are not part of an existing Xcode project. It also explains how to leverage an existing Makefile through Xcode to build an existing project without creating it in the Xcode GUI.
Chapter 25 attacks the question of how to make your application perform faster, unlike the performance of Xcode’s build itself. It explains how to use Shark, a statistical application profiler. Also described are a suite of CHUD (Computer Hardware Understanding Developer) tools for measuring other aspects of application performance. Chapter 26 describes the software instrumentation framework that is part of Mac OS X. This consists of a framework for instrumentation and an application called Instruments that displays the measurements. This framework is similar to the performance counter framework and the performance monitor application in Windows. Chapter 27 discusses some pitfalls you may encounter in Xcode development and some tips on using Xcode that aren’t immediately obvious.
That wraps up Part II, clocking with a total of 471 information packed pages. There are an additional 30 or so pages in the appendices and a good index in the back.
I would strongly recommend this book to anyone that is thrust into Xcode development, particularly if you are already familiar with another development environment. If you’re new to Xcode and Macintosh development this book would be a good complement to any book on Objective C and the Cocoa API.