This page contains my notes about Xcode, the IDE used for writing applications for Mac OS X and iOS devices (iPhone, iPad). For the moment, there is also a section about Interface Builder (IB), the RAD tool to develop the GUI of Mac applications.
- 1 Developer Tools
- 2 Xcode plugins
- 3 Xcode Preferences
- 4 Keyboard shortcuts
- 5 Xcode paths
- 6 Workspaces, projects, build configurations, targets, schemes
- 7 Non-admin account requires group membership
- 8 Precompiled Prefix Header
- 9 Adding a doxygen target to a project
- 10 Adding unit tests to a project
- 11 The Xcode build system
- 12 Customize new project
- 13 Debugging with Xcode
- 14 Instruments
- 15 Interface Builder (IB)
- 16 References
Since version 4.3, Xcode is distributed as a standalone app bundle. A number of additional developer tools that Apple now considers optional must be installed separately. Things I habitually install are
- Command line tools: These are required for software builds outside of Xcode, such as Fink, or builds of third party software packages that I use for my own projects. The easiest way to install these is from within Xcode: Open the Preferences dialog, then go to Downloads > Components, select the entry "Command Line Tools" and click the install button.
- iOS simulator applications for older versions of iOS: These can also be installed from within Xcode in the same way as the command line tools.
- Graphics Tools for Xcode: One of the most useful applications in this tool suite is Pixie, which allows to inspect displayed graphics on a pixel level with a "magnifying glass" effect. From within Xcode, select the menu entry "Xcode > Open Developer Tools > More Developer Tools...". This opens a browser window that shows all additional Xcode tool packages. The Graphics Tools package should be among these.
- Audio Tools for Xcode: See "Graphics Tools" for how to get at these tools.
- Auxiliary Tools for Xcode: See "Graphics Tools" for how to get at these tools.
Xcode plugins use the extension
xcplugin. Installing a plugin is very simple, just drop it into
Create the directory if it does not exist yet. To install a plugin system-wide, on Mac OS X 10.6 it needs to be dropped into
- GTMXcodePlugin from the Google Toolbox for Mac: Provides an option to trim trailing whitespace when a file is saved. Note that this plugin is no longer necessary as newer versions of Xcode now have an official user preference for this.
These settings refer to the Preferences dialog as shown in Xcode 4.5.
- Running completes
- Hide debugger = true (default = if no output, hide)
Text Editing > Editing
- Line numbers = true
- Show column position = true
- Page guide = true, at column = 80
- Automatically trim trailing whitespace = true
- Including whitespace-only lines = true
- Default text encoding = UTF-8
- Default line endings = OS X / Unix (LF)
- Convert existing files on save = false
Text Editing > Indentation
- Prefer indent using = Spaces
- Tab width = 2
- Indent with = 2
- Tab key = Indents in leading whitespace
- Line wrapping = false
- Align consecutive // comments = true
- See section Xcode paths
- The "Archives" location should be changed to something like
/Users/foo/dev/Xcode Archivesso that the archived builds are indexed by Spotlight. Without Spotlight indexing, symbolicating crash logs will probably fail. For details about symbolicating see the wiki page on Mac OS X Programming.
- File > Project Settings > Snapshots > Create snapshot of project before mass-editing operations = false
- I don't see the use for snapshots when Ialso use version control
- In the past this automatic-snapshot feature made it virtually impossible for me to use refactoring because the snapshot would include the entire project directory with all third party software builds inside (hundreds of MB)
- Get rid of the warning message box when you undo after saving a document (note: this is probably no longer necessary for Xcode 4.5):
defaults write com.apple.Xcode XCShowUndoPastSaveWarning NO
These shortcuts are defaults in Xcode 4.5:
- Close document = Ctrl + Command + W
- Jump to next/previous counterpart = Ctrl + Command + Cursor Up/Down
- Open quickly = Command + Shift + O
- In the window that opens just start to type to incrementally filter possible documents to open
- The word under the cursor is used for initial suggestions
- Commit dialog = Alt + Command + C
- Use selection for Find = Command + E
- Unlike a similar function in Visual Studio (Ctrl+Tab) this does not immediately perform a search
- To follow up with a "search next", press Command + G
Changes to defaults
- Build results
- By default these are stored in
- This folder can be changed to a project-relative path under "Preferences > Locations > Locations > Derived Data"
- Archives and Snapshots
- By default these are stored in
- These folders can be changed under "Preferences > Locations > Locations"
- Symbols downloaded from an iOS device
Workspaces, projects, build configurations, targets, schemes
- Information on workspaces, schemes etc., including interesting links to the underlying documentation from Apple: http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/
- A workspace is a container for one or more projects
- A project contains
- One or more build configurations
- One or more targets
- One or more schemes
- The actual source code and resource files (obviously)
- A build configuration is just a name. Typically there are two build configurations: Debug and Release.
- A target is a collection of the following things:
- For each configuration, a collection of build settings
- For each configuration, a definition of which source code files need to be built
- For each configuration, a definition of additional files that belong to the target/configuration, usually resource files
- A scheme is a collection of the following things:
- It contains one or more targets
- It defines what happens for each of its targets when one of the actions in the "Product" menu is executed: Build, Run, Test, Profile, Analyze, Archive
- The definition for each action includes which build configuration to use
- A target is inactive until it is associated with at least one scheme
A workspace's data is stored in a folder that has the extension
The Finder treats the folder as a bundle, i.e. for the user it appears a file that can be double clicked.
Example workspace content
caradhras:~/dev/littlego --> cat "Little Go.xcworkspace/contents.xcworkspacedata" <?xml version="1.0" encoding="UTF-8"?> <Workspace version = "1.0"> <FileRef location = "group:Little Go.xcodeproj"> </FileRef> <FileRef location = "group:Pods/Pods.xcodeproj"> </FileRef> </Workspace>
Non-admin account requires group membership
If you are logged in as a normal (non-admin) user, when you select "Build and debug" for the first time in Xcode you will be asked for the admin password. This happens once every login session. I am on Snow Leopard and use Xcode 3.2.5.
This is rather unexpected, but the Xcode release notes indeed mention that this is the case in the current seed of the developer tools, but that "the security mechanisms and policy here are still under development for Snow Leopard, and may change further in later seed releases.". In the same release notes, but on another note, the following explanation appears: "All Xcode operations that operate between processes now require authenticated administrator privileges. In the optimal case, you will be asked to authorize developer privileges only once, and that authorization will be stored in your Keychain."
The "optimal case" certainly does not apply here, as the query appears every time I log out and log in again. It appears, though, that the problem can be circumvented by giving the non-admin user membership of a certain system group:
sudo dscl . append /Groups/_developer GroupMembership patrick
Precompiled Prefix Header
Information in this chapter is taken from the chapter "Using a Precompiled Prefix Header", section "Reducing Build Times", article "Xcode Build System Guide" (located under ADC Home > Reference Library > Guides > Tools > Xcode).
A "precompiled prefix header" is a header file that is
- included automatically at the beginning of each file of a target
- there can be only one such file per target
- but one file can be shared among multiple targets or projects
The header file can be shared among multiple targets, or even projects. Because of this, and because different targets/projects may contain source files written in different programming languages, it is recommended that the precompiled prefix header contain appropriate guard macros, such as this:
#ifdef __OBJC__ #import <Cocoa/Cocoa.h> #endif #define MY_CUSTOM_MACRO 1 #include "MyCommonHeaderContainingPlainC.h"
To configure Xcode to use a precompiled prefix header, change the following build settings of the appropriate target, or maybe even of the entire project:
- GCC_PREFIX_HEADER (Prefix Header). Change the value of this build setting to the project-relative path of the prefix header file
- GCC_PRECOMPILE_PREFIX_HEADER (Precompile Prefix Header). Make sure that this option is turned on.
Note: When the Xcode wizard creates a new project, it helpfully adds a precompiled prefix header to the project which imports <Cocoa/Cocoa.h>. Unfortunately the header is not used because the appropriate build settings are disabled.
Adding a doxygen target to a project
Documentation about managing targets can be found in "ADC Home > Reference Library > Guides > Tools > Xcode > Xcode Build System Guide".
The following procedure adds Doxygen support to a project:
- Prepare the project with these steps
- Add a doxygen folder
- Inside that folder, generate a template Doxygen configuration file (named Doxyfile) like this:
- Inside Xcode, add the Doxyfile to the project so that you can edit it conveniently in the Xcode editor
- Manually modify the following options within the Doxyfile:
PROJECT_NAME = <the project name> FULL_PATH_NAMES = NO EXTRACT_STATIC = YES INPUT = .. FILE_PATTERNS = *.h *.m RECURSIVE = YES EXCLUDE_PATTERNS = */.git */build GENERATE_LATEX = NO HAVE_DOT = YES DOT_PATH = /sw/bin
- Create the new target in Xcode
- Select "Project > Add Target" from the menu. This opens the "New Target" wizard.
- From the category "other", select the target type "Shell Script Target"
- On the next page specify these properties:
- Target name = doxygen
- Add to project = the project
- Click the "Finish" button to create the target
- Configure the target
- Find the new target in the Group Tree pane, then expand the target
- A build phase entry named "Run Script" appears; open the Info window for the build phase entry
- The actual shell script can be added on the "General" tab. This is what I usually put in:
# change directory because Doxyfile is configured with a relative input path ".." cd doxygen # clean the directory rm -rf html # generate docs /sw/bin/doxygen Doxyfile # open the html documentation open html/index.html
Adding unit tests to a project
The xUnit unit testing suite has been ported to Objective-C by Sen:te, under the name of OCUnit. At some time in the past, Apple has started distributing OCUnit as an integral part of XCode.
Apple distinguishes two types of tests:
- Logic tests: This is the traditional type of unit tests where "only" specific classes are tested in a rather narrow environment. In iPhone development, logic tests are built using the iOS Simulator SDK, but they are run outside of the simulator, right after Xcode has finished building the unit test target.
- Application tests: This type of unit test focuses on exercising the application as a whole. In iPhone development, application tests are built into a test bundle that is then embedded into the application bundle and executed on the device itself. This allows to run tests in a realistic production environment, including tests that exercise code that requires hardware capabilities of the device.
- This article on mobileorchard.com has a short, slightly outdated, step-by-step introduction on how to add unit tests to an Xcode iPhone project
- This article on developer.apple.com is more in-depth, and also focuses on iPhone development
- Unit-Test Result Macro Reference
Create a top-level folder named "test" that will contain all test-related files. Add the following subfolders
- src = contains unit test source code files
- resource = contains resources required by unit tests
- testdata = contains other test data files
Add new unit test target
- Select Project > New Target...
- The target type is "Unit Test Bundle" and can be found either under the category "Cocoa Touch" or under the category "Cocoa"
- Select the category that matches the project type
- Target name = "Unit tests"
Modify the new target's build settings
- Base SDK = Remove custom value so that the target inherits the project-wide setting
- Header Search Path = ./src (since the test sources are completely separated from the normal application sources, we don't want to deal with relative path issues for each
#importstatement; the application can be seen as third party software from the point of view of the unit test bundle)
- Precompile prefix header = Yes
- Prefix Header =
src/Prefix.pch(or whatever file is the prefix header of the project)
- Add all classes for which test cases are written to the unit test bundle
- An alternative (and preferrable) approach would be to build the application as a static library, and then to link the unit test bundle against that library
- Unfortunately this approach cannot be chosen because I have not yet found a way how to link the real application against the static library
- When the new target was created, Xcode automatically added an Info.plist file for that target to the project (e.g.
- The file is located in the project's top-level folder, but we want to move it to
- Update the build setting (under "Packaging") that refers to the file (e.g.
- Make sure that the file is not copied
Add a test case file
- Context menu for
test/src> Add > New File... > Cocoa Touch Class (or Cocoa Class) > Objective-C test case class
- File name = does not matter
- Targets = "Unit tests" (not the project's main target!)
Test case characteristics
- File and class name are irrelevant
- Class must inherit from
- Test method name must begin with
test(lower case), the method must have no parameters and return
- Building the target automatically runs the unit tests
- The target has an additional "Run Script" phase which invokes
The Xcode build system
Compiling projects from the command line
To build an Xcode project on the command line, you use the utility
Also see the man page. Some examples
# List all targets, and all configurations of a project xcodebuild -list # Use -project if there are multiple .xcodeproj in the current working directory xcodebuild -project Foobar.xcodeproj -list # Build the first target in the project, using the default configuration xcodebuild # ditto, but build the active target (the active target is the one selected in the GUI) xcodebuild -activetarget # ditto, but build target "foo" xcodebuild -target foo # ditto, but build all targets xcodebuild -alltargets # ditto, but use the active configuration for the build (the active configuration is the one selected in the GUI) xcodebuild -alltargets -activeconfiguration # ditto, but use the configuration "foo" for the build xcodebuild -alltargets -configuration foo # Perform the action "clean" instead of the default action "build" xcodebuild -alltargets clean # Perform the actions "clean" and "install" (build + install) xcodebuild -alltargets clean install # List all available SDKs xcodebuild -showsdks # Use SDK "iphonesimulator4.2" for the build. In the Xcode GUI this SDK is displayed as "Simulator" xcodebuild -sdk iphonesimulator4.2 # ditto for SDK "iphoneos4.2". In the Xcode GUI this SDK is displayed as "Device" xcodebuild -sdk iphoneos4.2 # Build only for architecture "armv6" (the default is to build for all architectures) xcodebuild -sdk iphoneos4.2 ARCHS=armv6 # Build for multiple architectures xcodebuild -sdk iphoneos4.2 ARCHS="armv6 armv7"
Details about the build system
The Xcode build system is based on the concept of "targets" - not exactly a surprising thing.
- A target is composed of a series of build phases
- Each build phase performs an action on one or more files that are part of the target
- Example build phases for a simple "Cocoa Application" target
- Copy bundle resources
- Compile sources
- Link binary with libraries
- The target type usually determines which build phases there are (e.g. a "Shell Script" target has different phases than a "Cocoa Application" target)
- To modify the build behaviour, a large number of "build settings" can be made, usually either on the project or the target level
- Examples for build settings are compiler or linker flags, which architectures to build, etc.
- List of sources of build settings, and their precedence
- The target
- The project
- Xcode application preferences
- Xcode's built in defaults
- The user environment (e.g.
- Build configurations (e.g. Debug, Release) are collections of build settings
Build configuration files
- Build settings by default are stored in the Xcode project, but they can also be placed in one or more external files called "build configuration files"
- These files usually have the extension
- One useful scenario for
.xcconfigfiles is if multiple projects should share a set of common build settings
- The settings in an
.xcconfigfile usually relate to a single build configuration
.xcconfigfile is a simple text file with property/value pairs; e.g.
ZERO_LINK = NO GCC_OPTIMIZATION_LEVEL = -O0 GCC_GENERATE_DEBUGGING_SYMBOLS = YES
- The build configuration file must be added to a project in order to become available within the project
- Once the file is part of the project, a build configuration (e.g. Debug) can be based on the file -> this can be done inside the appropriate Info Inspector window
- The snippet from the Xcode project's
.pbxprojfile looks like this:
baseConfigurationReference = 65F688F1A6A7B5ADEF3706EA /* Pods-Little Go.debug.xcconfig */;
- The string
65F688F1A6A7B5ADEF3706EAis merely a reference to the actual
.xcconfigfile that is defined elsewhere in the
- Every target has a set of associated build rules -> refer to the target's Info Inspector window
- Each rule tells the build system how to process a certain file type
- For instance, the "System C" rule defines that "C source files" should be processed using "GCC System Version"
- Most of the time, a target will have only the built-in rules, but it is possible to define custom rules
- File types in a custom rule are defined either by selecting from built-in file types, or via a file pattern (e.g.
- Processors in a custom rule are defined either by selecting from built-in processors, or via a custom command or script
- In addition to file type and processor, the rule must also specify the output file(s) - presumably so that the build can check whether a target is up-to-date or needs processing
Useful build settings
- Determines the architecture(s) of the build
$(NATIVE_ARCH)refers to the architecture of the machine that the build is taking place on
- Other architectures are: i386, ppc, armv6, armv7
- To make a universal build, specifiy ARCHS="ppc i386"
Customize new project
Change default project structure
When Xcode creates a new project, the project structure is not entirely to my liking. Changing things is not entirely straightforward, therefore this section documents a few things.
Regular sources (.h and .m files) can simply be re-added after they have been physically moved. Xcode will automatically add .m files to the build target, while .h files are automatically excluded.
Note: The file
main.m counts as a regular source file.
The project-specific precompiled header file
Foobar_Prefix.pch can be simply re-added after it has been physically moved. It should not be added to the build target. In addition, the following references have to be updated:
- Build target, all configurations: Under "GCC 4.2 - Language", the property "Prefix header" must be updated (to find references, you may want to search for "prefix")
Interface Builder (IB) files (.xib files) can be simply re-added after it has been physically moved. They should be added to the build target.
The Info.plist file can be simply re-added after it has been physically moved. It should not be added to the build target. In addition, the following references have to be updated:
- Build target, all configurations: Under "Packaging", the property "Info.plist" must be updated (to find references, you may want to search for "Info.plist")
Debugging with Xcode
How to debug EXC_BAD_ACCESS
The reason for getting an EXC_BAD_ACCESS error message usually is a message being sent to an object that is already deallocated. If the cause for the problem is not immediately apparent, the situation is often hard to debug since you can't inspect the object in question. The solution are "zombies".
When this feature is enabled in Xcode, a dummy object (a zombie) is kept at the memory location of a released object. Inspection of the dummy object often provides valuable clues as to what happened. Enabling of zombies in Xcode 4 is very easy:
- Product > Edit Scheme
- Select the "Run" action
- On the "Diagnostics" tab, check the "Enable Zombie Objects" checkbox
Note: Don't forget to disable zombie support after you are done with debugging.
The easiest way to run Instruments is from within Xcode:
- Select the menu item "Product > Profile"
- When Instruments launches you are prompted with a selection of trace templates that are appropriate for the target you are profiling (e.g. you won't get iOS templates if you are profiling a Mac OS X application)
A useful option is "Gather Leaked Memory Contents":
- Select the "Leaks" instrument
- In the detail view a number of categories appear on the left-hand side
- One of them is the category "Leaks configuration"; below that category you will find a checkbox labelled "Gather Leaked Memory Contents"
- Click the checkbox
- To actually see the memory content, select the menu item "View > Extended Detail"
- When you select a leak you will now see a stack trace and a hex view of the memory content that was leaked
Leaks from the command line
- Run the program from within Xcode
- Execute the following command in Terminal.app
leaks <pid> | less
- You will get a nice overview of all leaks
- Most important: You will get an ASCII representation of the hexdump
Use this instrument to find memory that is "lost" instead of leaked. Similar to leaks, lost memory is allocated but never freed, but the difference is that there is still a reference to the memory block hanging around somewhere. This is why the Leaks instrument won't find this type of problem. Possible sources for lost memory
- Retain cycles where two objects reference each other, but nothing else refers to those two objects
- Forgotten dictionary entries
- Probably more, but the two examples above are what comes to mind immediately
Notes about using the Allocations instrument
- It must be configured to use the "Created & Still Living" option
- Bring the application into a stable state where no allocations are happening
- Perform an operation
- Undo the operation, or use some other means to bring the application back into the stable state from where you started
- Possibly wait some time until your app activity has died down
- Memory usage should now be exactly the same as when you started the initial operation
- In addition the following might apply to the application
- Apply a time filter to the Allocations track so that only allocations in the time between the start and the stop of your operations are taken into account
- You should now see zero net values in the columns "Live Bytes" and "# Living", i.e. all objects that were created in the filtered timespan have also been destroyed
- Whether or not this works depends, of course, on how the application is implemented - if the application replaces existing objects with new objects, net values will not be zero and this type of examination will not provide useful results.
Interface Builder (IB)
This chapter contains various tidbits related to working with Interface Builder (short: IB). The main ressource for IB-related documentation is the "Interface Builder User Guide" 
What is a .nib file?
- nib = NeXT Interface Builder,
- A .nib file contains an archived version of a set of GUI elements, and/or other non-visual elements (such as controllers) that are responsible for managing the GUI elements
- The content of a .nib file is edited with the Interface Builder application
- When a .nib file is loaded, its content is unarchived and the objects defined within the archive are re-created exactly as they were present when the file was last edited with Interface Builder
- IB version 3 introduced a new file format, using the extension .xib, which is functionally identical to .nib, but stores its content in a flat file. This is much more suitable for storing the file in SCM systems, and makes it also easier to process the file with tools like
What is the "File's Owner"?
- The "File's Owner" object is the "controller" object that is responsible for (the owner of) the contents of the .nib file
- When the .nib file is loaded, the File's Owner object must already exist
- All the other objects inside a .nib file are created at the time that the .nib file is loaded
- When the .nib file is loaded, the nib loading code restores any outlet connections defined in the .nib file
- The File's Owner object thus becomes the link between the .nib file and the rest of the application code
- The File's Owner object of the application's main .nib file is the
What is an outlet?
- Represents a member variable of the class that the outlet belongs to
- An outlet has a type
- An outlet is defined in the "Classes" view, in the Info window -> Attributes
- In the "Instances" view, control-drag from an instance A to a different instance B; this allows to connect an outlet within instance A to the instance B (if the outlet has a type that matches the type of instance B); when the .nib is loaded, the outlet's member variable of instance A will have a reference to instance B
What is an action?
- Represents a method of the class that the action belongs to
- The method signature must look like this: (void)myAction:(id)sender;
- With Java, it is important that the name of the argument is "sender"
- An action is defined in the "Classes" view, in the Info window -> Attributes
- In the "Instances" view, control-drag from an instance A to a different instance B (possible only if A is a control); this allows to connect the control to one of the target's (instance B) action method
How to define a button that should react to the Enter, Escape or any other key being pressed:
- Info window -> Attributes -> Equiv
How to define the first element that should be active when a window is opened:
- Select the NSWindow instance
- Control-Drag from the instance to the element that should be active
- Info window -> Connections -> Outlet -> initialFirstResponder
- Click the "connect" button
How to define tabbing between two elements:
- Select first element
- Control-Drag to the second element
- Info window -> Connections -> Outlet -> nextKeyView
- Click the "connect" button
How to define the NSApplication delegate:
- Select the "File's Owner" instance in the main .nib; this is the NSApplication object
- Connect the outlet delegate of the "File's Owner" instance to the desired delegate instance
- Some of the messages that the delegate receives are sent by NSApplication itself (e.g. applicationOpenFile), others are sent by the application's default notification centre (the delegate is automatically registered with the default notification centre if it implements methods that correspond to the delegate messages)
- The documentation for NSApplication lists the 20+ delegate methods