Xcode 4 has been out for a while now, but a lot of people are still uncomfortable with its interface and find it awkward to use. I am not in that group, as I’ve actually quite liked the way things are setup overall. This is probably largely because it’s similar to the way I was using Xcode 3 already, in a mostly single-window fashion, but I think I’ve also discovered a few tricks to help ease various parts of my workflow. Many others have probably already discovered these, but I thought I’d share them just in case they prove helpful to anyone.
One Tab Per Task
Tabs are an essential part of my Xcode workflow. I was skeptical of Xcode 4 until I a) discovered it had tabs, and b) discovered some of the details of how they are implemented by Xcode. Heck, I’ve seen some people who still don’t even realize the ability to make tabs exists! After all, they are hidden by default, with no visible tab bar.
Now, with most applications that support a tabbed interface, each tab is typically used to hold a single document, so that you can switch easily between them. I tried this with Xcode 4, but quickly found that the set of files I’m working with at any given time is usually too large for tabs to really be an effective way of managing them. The number of tabs would quickly grow to where I couldn’t find anything, and didn’t end up saving me any time. The key realization I had was that, rather than having one tab per file, I should instead have one tab for each type of task, such as editing, building, debugging, and so forth.
One important aspect of Xcode that makes this work well is the fact that each tab remembers its own configuration. This includes things like:
- Whether the navigator pane (on the left) is visible, and how wide it is.
- Which navigator is active in the navigator pane (e.g. project, issues, logs, etc.)
- The filter field and other options at the bottom of the navigator pane.
- All the analogous stuff for the utilities pane (on the right).
- Whether the debugger is visible, its size, and whether the variables and/or console is visible
- Whether the assistant or version editor is enabled.
One thing I’ve seen that annoys a lot of people about Xcode’s interface is that they’re constantly having to fiddle around with resizing things, showing/hiding the navigator/utilities pane, switching the assistant editor on/off, showing/hiding the debugger, and so forth. However, since each tab can remember its configuration, that means you can specialize each tab to handle a particular type of task, and use that tab for that task. You can even give a custom name to each tab by double clicking its name in the tab bar, which will let you type in a name other than that of the currently open file. (this is very non-obvious, and I had to be tipped off by an Apple engineer that this was even possible)
OK, having a different tab for each type of task is fine and all, but that means I still have to switch around tabs all the time, right? Well, not necessarily. With the generous use of the Behaviors capability of Xcode, you can actually automate a lot of the tab switching to happen at the appropriate times. If you’re not familiar with Behaviors, open up the preferences window and click on the Behaviors icon there.
For example, if you have a tab set up specifically for debugging, you can set the “Run pauses” behavior to show the tab named “Debug”, show the debug navigator, and show the debugger pane. That way, whenever you hit a breakpoint, you’ll automatically be switched to that tab, with everything set up and ready to debug your code.
Also worth noting is that you can make your own custom behaviors, using the “+” button down at the bottom of the preferences window, and then assign a custom keyboard shortcut that will trigger that behavior. I’ve co-opted the command-1, command-2, etc. shortcuts, which are used by default by the navigator panes, and instead use them to switch quickly between my custom tabs. This way, anything that can’t be trigger automatically by a built-in behavior, you can instead switch manually without having to take your hands of the keyboard.
To give some concrete examples of what I’m talking about above, I thought I’d just give a quick run through the way I have my own tabs setup. Your workflow will almost certainly differ from mine, but hopefully this will give you some ideas on how you can customize things to the way you work. For context, I generally work on a 1920x1200 display (17” MBP or 24” LED Cinema Display), either in Lion full screen mode or with the Xcode window maximized. I have custom behaviors set up with keyboard shortcuts command-1 through command-6 which let me switch to each of my 6 tabs easily.
My first tab is used for source code editing, and is generally where I spend the bulk of my time. I like to always have the assistant editor activated and set to “Manual”, so I have two editors side by side. I almost never need to use anything in the utilities pane while editing source, so I keep it closed to give more horizontal space for my two editors. Since I do most of my file navigation using either the jump bar or the “Open Quickly…” menu command, I usually have the Find navigator open on the left, for doing batch find/replace in my project. I of course use the Project navigator whenever I need to mess with my groups or files.
- Editor Type: assistant, manual
- Utilites Pane: hidden
- Navigator Pane: find navigator
- Debug area: hidden
- Behaviors: none
As I described a bit above, I have my debugger tab set up so that the debug area is always shown, so I can see variables and the console. The debug navigator is visible, but the utilities pane is hidden. I keep an assistant editor open, which I don’t end up using that often, but it’s usually more useful than having my source file fill the entire width of my screen. The “run pauses” behavior is set up to switch to this tab, and configure it as described, in case anything had previously been set otherwise.
I use this tab for viewing and dealing with issues generated by building, testing, or analyzing code. The workflow that seems to be intended by the Xcode team is to use the Issues navigator to view your build errors/warnings. I, however, hate the Issues navigator. It’s too narrow, it truncates error messages, and it doesn’t let you easily see further details about the problem.
So instead, my setup is to have the “Build generates new issues” behavior set up to a) show the build tab, b) show the log navigator (not the issues navigator), and c) navigate to the current log file. What this does is to show the full build log for the most recent build in the standard editor, which shows all the same issues as the issues navigator, but lets you expand each one to see more details, view the full command line invocation of each build step, and see the environment variables being used for things like shell scripts.
I then have the assistant editor enabled, and set to the “Reference Files” mode in the jump bar. This causes clicking on an issue in the build log to display the relevant file and line in the assistant editor on the right, where I can then correct it. I find this setup to be much better for handling build errors than the default.
One of my favorite parts of the UI revamp done in Xcode 4 is the way that target/project settings are done. The new unified view of how all the build settings are applies is sooooooo much better than the zillion different info windows you had to open up with Xcode 3. To give this the space it deserves, I don’t use the assistant editor in this view, but use the “Levels” view of the project settings. The full screen width gives plenty of space to view the default, project, target, and final build settings side by side.
The project navigator is open on the left, and I have “.xcodeproj” typed into the filter field at the bottom, so that all the projects and sub projects in my workspace are easily visible and can be selected there. The filter string is even remembered by Xcode between relaunches, so you only have to type it in once. I usually also have the utilities pane open, set to the Quick Help inspector, for an easy cheat sheet on whatever build setting I currently have selected.
- Editor Type: standard
- Utilites Pane: quick help inspector
- Navigator Pane: project navigator, “.xcodeproj” filter
- Debug area: hidden
- Behaviors: none
This tab is a bit of a dual use tab, and is used for both Interface Builder files and Core Data Model files. The main key here is that I want to have a big canvas for moving these objects around on, so I have the standard editor in effect here most of the time. When I’m hooking up outlets and actions though, I will sometimes switch to the assistant editor, to allow easy drag and drop between the interface element and the corresponding header file.
The utilities pane is very important for both of these, so it is always open, to allow for editing of the attributes of whatever object is selected in the main canvas. The Object Library is also open at the bottom, to be able to drag new objects into the model file. I also have the project navigator visible on the left, and have “.xib” entered in the filter field down at the bottom, so that all my IB files are easily accessible from there.
The one thing that’s missing here that I’d like to see in a future version of Xcode is some way to automatically switch to this tab, but only when I’m opening a .xib or .xcdatamodel file. As it is now, I have to remember to manually switch to that tab first before opening a model file. I’m actually not sure what the best way to implement this in Xcode would be - perhaps some way to assign a custom behavior to trigger when opening a certain file type?
- Editor Type: standard/assistant
- Utilites Pane: open w/object library
- Navigator Pane: project navigator, “.xib” filter
- Debug area: hidden
- Behaviors: none
80% of the time, the smallish console area in the debug tab is enough to view whatever messages are being spit out during a debugging session, but I find fairly often that I need a bigger viewport for reading the console. So, I have a tab dedicated specifically for this purpose. I usually switch to this tab when I’m already in the debug tab, so I have my command-6 behavior set up to do the dirty work. It a) switches to the Console tab, b) shows the debug navigator, c) shows the debugger with Console View only. I then take the horizontal divider between the source code and the console and drag it all the way to the top, so that the console takes up the entire area of the window. This gives me a giant console view for reading through lots of text.
- Editor Type: standard, but it’s hidden anyway
- Utilites Pane: hidden
- Navigator Pane: debug navigator
- Debug area: shown, console only, dragged all the way to the top
- Behaviors: keyboard shortcut only
So anyway, I hope this description of things gives you some ideas for how to set up Xcode 4 to better fit the way you work. There’s obviously still a lot of room for improvement, but I think things have evolved significantly even since 4.0 came out, so if you haven’t looked much at your workflow in the last couple versions of Xcode, it might be worth revisiting to see if you can automate some of these things to save time and hassle.