1. Migrating from a cell-based to a view-based NSTableView

    As I mentioned in my last post, I’m currently learning about how a view based NSTableView differs from an old style NSCell based table view (or technically in my case, an NSOutlineView). I’m taking notes on what all is different, and figured I’d post it here too, in case it helps anyone else

    Like before, you can use either bindings or a data source to provide data to your table view.

    However, with cell based views, you would bind each individual column, or provide different object values for each row+column in -tableView:objectValueForTableColumn:row: With view-based tables, it’s just a single ‘content’ binding that binds each row to an object value, and that same object value is set as the objectValue for each of your cell views. Each view can show different data by binding to different properties of the objectValue, e.g. the name column would bind to “objectValue.name”, etc.

    With a data source, you don’t actually need to implement -tableView:objectValueForTableColumn:row:, as you can just configure your view yourself before returning it from -tableView:viewForTableColumn:row:. However, you can implement the object value data source method if you want, and NSTableView will do just like bindings, and use that as the objectValue for the cell view.

    Editing cells is no longer handled by the table view itself, and doesn’t call a setObject data source method to pass on the value. Instead, you’re supposed to use bindings or hook up target/action from the subviews in your cell’s view to modify the model object as needed. NSTableCellView handles this mostly automatically for you though. This does make it much easier to have a single cell handle editing multiple bits of data though, if needed, since you no longer have to work under the assumption that one cell displays just one value.

    This also means that starting an edit programatically works a bit differently too, since NSTableView is no longer doing the work of setting up the field editor for your NSTextFieldCell like it did before. According to the docs, it tries to make the view in that row/column the first responder, and then it’s up to the view to start editing? Or something? I need to play with this one to figure out how it really works.

    With cell-based tables, each table column just had a single NSCell instances, stored in its dataCell property. You could give it custom cells using the -tableView:dataCellForTableColumn:row: method, to have different types of cells in different rows. For view-based tables, you can just drag multiple views into a single table column, and give each one a unique identifier string. Then you can just call -makeViewWithIdentifier:owner: to have it make a new instance of that view each time you need it. This makes it really easy to have heterogenous cells in your table.

    That’s all I’ve got for now, I’ll post more if I discover anything else as I go along.

     

  2. -[NSTableView makeViewWithIdentifier:owner]! How Does It Work!?

    So, I’m finally getting around to learning about view based NSTableViews, which were introduced in OS X Lion, with the intention of converting my app PlistEdit Pro to use the new type of table/outline view.

    I started by reading through the docs, and looking at the TableViewPlayground sample code. Everything mostly made sense, but there was one part I couldn’t quite understand, which was the usage of the -makeViewWithIdentifier:owner: method. More specifically, I understood how you were supposed to use it, but I couldn’t figure out how it worked. I guess I’ve become less tolerant for letting things remain “magic”, so I decided to do some digging and see if I could figure out how this thing was implemented.

    To start with, here’s how this method is typically used:

    (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {

    // Retrieve to get the @"MyView" from the pool or,
    // if no version is available in the pool, load the Interface Builder version
    NSTableCellView *result = [tableView makeViewWithIdentifier:@"MyView" owner:self];

    // Set the stringValue of the cell's text field to the nameArray value at row
    result.textField.stringValue = [self.nameArray objectAtIndex:row];

    // Return the result
    return result;
    }

    And here’s what the docs say about the method:

    Typically, identifier is associated with a cell view that’s contained in a table’s nib file. When this method is called, the table view automatically instantiates the cell view with the specified owner, which is usually the table view’s delegate. (The owner is useful in setting up outlets and target/actions from the view.) Note that a cell view’s identifier must be the same as its table column’s identifier for bindings to work. If you’re using bindings, it’s recommended that you use the Automatic identifier setting in Interface Builder.

    This method may also return a reused view with the same identifier that is no longer available on screen. If a view with the specified identifier can’t be instantiated from the nib file or found in the reuse queue, this method returns nil.

    This method is usually called by the delegate in tableView:viewForTableColumn:row:, but it can also be overridden to provide custom views for the identifier. Note that awakeFromNib is called each time this method is called, which means that awakeFromNib is also called on owner, even though the owner is already awake.

    When you set up a view based table view in Interface Builder, you can drop a view onto one of your table’s columns, and give it an identifier using the inspector. This is the identifier that you pass into -makeViewWithIdentifier:owner:. Easy peasy.

    However, each time you’re calling this method, “the table view automatically instantiates the cell view with the specified owner”. Instantiates how exactly? This certainly seems to imply it does so by the normal nib loading mechanism, which is further supported by the owner: argument, and the warning in the docs about awakeFromNib being called multiple times when using this pattern. But this view is embedded inside a table column inside your table view, which itself is archived along with whatever other objects are in the same nib file. Is it really going to instantiate this entire nib file again, just so it can go in and pluck out this one cell view, then discard the rest? Or is it using some other mechanism entirely, like calling -copy on an existing view? Neither explanation seemed right, so I started digging a bit further.

    I started by taking the .xib file from the TableViewPlayground project and looking at the raw XML, so I could try to figure out how and where those cell views are stored. Opening it up in BBEdit, I found the section containing the information for the table column, which looks like so:

    image

    OK, so it looks like NSTableColumn has this “prototypeCellViews” key where those views that you drop onto the table column get stored. This obviously isn’t exposed in the public API, but it does explain where those views are stored, and how you can manage to put multiple cells with different identifiers inside a single table column (unlike a cell based table view, where each table column only has one data cell of its own). But they’re still buried deep inside the nib file - how do you instantiate these things without loading everything else as well?

    The next step was to take a look at the compiled .nib file, which is created by Xcode when building your application, by running the ibtool command line tool, which translates the SCM friendly XML into the fast loading binary .nib format. If you look at this in HexFiend, it looks like this:

    image

    I’ve dealt with these some before, and they are actually blobs of archived data created by NSKeyedArchiver, which in turn ends up storing its data as a binary plist (thus the “bplist” value at the very beginning). If only I had some sort of property list editor that would let me view it…

    image

    Making your way through a raw keyed archive isn’t difficult, but it is a bit cumbersome. It basically ends up being a giant list of objects, all indexed by object ID numbers in that “$objects” dictionary. Whenever any object has a reference to another object, it uses the object ID to refer to the other object. So, to follow the graph down, you start with one ID number, find what it’s referencing, find that ID number in the big $objects dictionary, and repeat the process ad nauseum. Or, if you know what you’re looking for, you skip all that and just do a search! I did a find on “NSTableView”, and here’s what popped up:

    image

    Well that does look like a bunch of information an NSTableView would need, things like NSBackgroundColor, NSDelegate, NSEnabled, NSTableViewArchivedReusableViewsKey, NS- wait, reusable who in the what now? Let’s go further down that rabbit hole and see what ID 60 is all about…

    image

    Here’s how we can interpret object #60:

    1. It’s $class points to object ID 70. If we look down at object 70, it looks like that’s telling us that this object is an NSMutableDictionary.
    2. The dictionary has keys (NS.keys) and values (NS.objects). Looking at the first entry in each list, we have a key value pair with the key pointing the object 61 and the value pointing to object 63.
    3. Following those links, we see that the key is “SampleWindowCell”, which corresponds to the identifier this nib file has for a custom cell in its table view.
    4. The value is object 63, which appears to have… a bunch of NSNib related info. Wait, what?
    5. The class for object 63 is object 67, which we follow and see is in fact the NSNib class.
    6. Looking at that NSNibFileData key, that points us to object 64, which is a big old data blob.

    OK, so what the heck is that data blob then? Let’s copy all that hex data and paste into HexFiend:

    image

    Oooh, this looks familiar, doesn’t it? Looks like another keyed archive, doesn’t it? OK, let’s save this to a file and open it in PlistEdit Pro:

    image

    Looks just like when we opened MainMenu.nib! And if we dig around in the various objects here, it looks like it does contain the components for our SimpleWindowCell view object. That’s right, we’ve solved the mystery of how these cell views are loaded, and the answer is:

    Nibception!!!

    Yup, we’ve got ourselves a nib inside a nib here. That’s why it doesn’t have to reload the entire thing, it just reloads the smaller nib embedded as a data blob inside the main nib. The complete sequence of steps is:

    1. When you do your setup in Interface Builder, it saves the data for those cells in the prototypeCellViews section that we saw in the XML for the .xib file.
    2. When ibtool compiles the .xib file, rather than just embedding those views inside the table view like is normally done for subviews, it instead sucks each cell view into its own separate NSNib, uses NSKeyedArchived to encode the NSNib object to a data blob, then stores that data blob inside the parent .nib file that’s being created.
    3. When your program runs and loads the outer nib file, those cell views don’t get instantiated immediately. Instead, those archived NSNib objects get instantiated from the data blobs and stored internally by the NSTableView.
    4. Finally, when you call -makeViewWithIdentifier:owner:, that finds the appropriate NSNib object for that identifier, then calls -[NSNib instantiateWithOwner:topLevelObjects:], passing along the owner argument that you gave it.

    Now of course you don’t actually need to know this to use this API, but knowing how it works does put my mind at ease that there’s no funky magic going on, just some clever engineering from the folks at Apple.

    OR IS IT!?

    image

     

  3. How to keep App Store from updating old versions of Xcode

    Using the App Store to download and install Xcode updates is very convenient, especially since it can often download delta updates which are much smaller than redownloading the entire installer from Apple’s developer site. I’ve seen many people run into an issue when doing this though, where after you update Xcode, the App Store continues to insist that Xcode needs to be updated again, to the same version, and will happily let you download and install Xcode a second time.

    The most common reason for this is that developers will often want to keep old versions of Xcode around, e.g. if you are not ready to move to the new version of Xcode full time for doing production builds, and need to keep the old version around for a while. However, the App Store app is rather aggressive when it comes to finding apps that need updating, so if you have another version of Xcode laying around, it will find that old version and say “Hey, this needs updating!” even if the main copy in your Applications folder has already been updated. Needless to say, this is rather annoying, especially if you only discover it after it’s blown away an old version of Xcode that you wanted to keep.

    The mechanism it uses to do this is our old friend, Spotlight. If Spotlight can find an old version of Xcode, the App Store will happily update it. So, the trick you can use to prevent the App Store from doing so is to hide your old version(s) of Xcode from Spotlight.

    The way I do that is to create a new folder where I put any old versions of Xcode that I want to have around. Then, open System Preferences and go to the Spotlight pane. In the Privacy section, you can then add that folder to the list of folders Spotlight should ignore. For me at least, that does the trick, and keeps the App Store from mucking around with my old Xcodes.

    Note that this same trick should work for any App Store app that you want to keep around multiple versions of, not just Xcode.

     

  4. A workaround for AESendMessage() hanging on OS X 10.8.2

    Shortly after Apple released their OS X 10.8.2 update last week, I started receiving e-mails from iPhoto Library Manager users who were getting timeout errors when trying to use iPLM to transfer photos between iPhoto libraries. iPLM uses Apple events to communicate with iPhoto, and sends the events using the AESendMessage() API in the CoreServices framework. (it doesn’t use AppleScript for reasons of control and efficiency) After some investigation, I believe there is a bug in 10.8.2 that causes this problem, and thought I’d post my findings here in case any other developers were running into similar issues. The bug is filed as number 12424662 and can be found on Open Radar at http://www.openradar.me/12424662

    The basic outline of the problem is that sometimes a particular application will get into a state where any events sent to it using AESendMessage (or AESend, for that matter) would not be delivered to the target application, and AESendMessage would simply block until the timeout value was reached, then return an errAETimeout error code. Quitting and relaunching the target application doesn’t change anything, but logging out and logging back in usually seems to fix the problem, at least temporarily. It also appears to only affect one application at a time, e.g. if iPhoto breaks in this way, other apps on the system will continue to function just fine.

    After much experimenting with different things, I found a way I was able to get events to flow again, even with the target application in this state. When you set up an Apple event, one of the parameters you need to give is an “address” of the application to which you want to send the event. The Apple event system has several ways of specifying this address, the most common of which are by bundle identifier or by the application’s four character creator code. My code was using the bundle identifier, which looks something like this:

    NSAppleEventDescriptor* addressDescriptor = [[NSAppleEventDescriptor alloc] initWithDescriptorType:typeApplicationBundleID 
    data:[self.bundleIdentifier dataUsingEncoding:NSUTF8StringEncoding]]; 
    
    NSAppleEventDescriptor* newEvent = [[NSAppleEventDescriptor alloc] initWithEventClass:kAECoreSuite 
    eventID:kAEGetData 
    targetDescriptor:addressDescriptor 
    returnID:kAutoGenerateReturnID 
    transactionID:kAnyTransactionID];
    

    What I eventually discovered was, that if I instead used an address descriptor that specified the process ID of the target application rather than just its bundle identifier, then the event would be delivered normally instead of timing out. This of course requires that the application already be running, and requires a bit of additional code to fetch the process ID for the application. This sample code does just that:

    NSRunningApplication* runningApplication = [[NSRunningApplication runningApplicationsWithBundleIdentifier:self.bundleIdentifier] lastObject];
    pid_t pid = [runningApplication processIdentifier]; 
    NSAppleEventDescriptor* addressDescriptor = [[NSAppleEventDescriptor alloc] initWithDescriptorType:typeKernelProcessID bytes:&pid length:sizeof(pid)];

    I wrote up a sample project to demonstrate the problem for the bug report. Anyone interested can download the project here. Note that I have still not come up with a way to reliably get an application into this weird state, so running the sample app might not be particularly useful for most people, but you’re welcome to take a look at the code in any case. The “Use pid address” checkbox in the main window is the relevant one - the other checkboxes there were for a bunch of other variations I was trying out, none of which turned out to be the issue. You’re all welcome to play around with it though. :)

    My speculative theory is that somewhere in the bowels of the Apple event system, there’s some sort of mapping that it keeps to translate bundle identifiers into process IDs so that events can be delivered to the right app, and it keeps this updated as processes get launched/quit. Somehow on 10.8.2, this can get messed up for a particular application, and any events sent to that bundle ID get swallowed up never to be seen again. Sending directly to the process ID still works though, because it doesn’t need to rely on the messed up internal mapping. Update: It looks like there is a background daemon called appleeventsd which seems to be responsible for this. Killing that process resets things, so you can do that rather than doing a full logout. 

    I also saw one other developer, Michael Tsai, mention that he was getting similar reports from another program trying to target his app, SpamSieve, with Apple events. In his case, the events were being sent using typeSignature (the four char code for the app) instead of typeApplicationBundleID, but the symptoms were all the same, so it does appear that this problem can potentially affect any application on OS X once the internal state for it gets messed up.

    One additional tidbit, for those who don’t want to use NSRunningApplication (e.g. targeting 10.5 or earlier), this code can also be used to translate from a bundle identifier to a process ID (courtesy of Michael).

       ProcessSerialNumber psn;
       psn.highLongOfPSN = 0;
       psn.lowLongOfPSN = kNoProcess;
       while (GetNextProcess(&psn) == noErr)
       {
           CFDictionaryRef infoCF = ProcessInformationCopyDictionary(&psn, kProcessDictionaryIncludeAllInformationMask);
           if (infoCF)
           {
               NSDictionary *info = [(id)infoCF autorelease];
               NSString *identifier = [info objectForKey:(id)kCFBundleIdentifierKey];
               if ([identifier isEqual:@"com.c-command.SpamSieve"])
                   return [info objectForKey:@"pid"];
           }
       }
     
    

    So, hopefully this information will come in useful to some other developers out there. If anyone manages to find a way to reproduce this weird state reliably with a particular application, do get in touch, as I’d love to add that info both to this blog post and to my bug report with Apple.

     

  5. A script to see Time Machine progress via Growl

    During long Time Machine backups, I often find myself checking the console for messages from backupd indicating how progress is going, especially when it has to delete a bunch of old backups to make room for the new one, which can take quite a bit of time. I found myself wishing I could just be notified via Growl whenever a new messages popped up in the console, rather than having to check it myself. So, being a programmer, I naturally wrote a script to do it for me.

    The script relies on the growlnotify command line tool, one of the extra downloads that you can get with Growl, so you’ll need to download and install that tool first. It’s written in Ruby, and uses the syslog tool to read the messages and then pipe them into calls to growlnotify, so they appear on the screen as Growl notifications. You can find the script as a gist on Github at the link below.

    Time Machine Growl script

     

  6. How to make Xcode’s UI work for you (maybe)

    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.

    Tab Configuration

    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)

    Behaviors

    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.

    My Tabs

    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.

    Edit

    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
    • Screenshot

    Debug

    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.

    Build

    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.

    Project

    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
    • Screenshot

    Model

    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
    • Screenshot

    Console

    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
    • Screenshot

    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.

     

  7. Debugging an ARC Mac application on Snow Leopard

    I’m currently developing a Mac application which uses Apple’s relatively new Automatic Reference Counting (ARC) in place of manual memory management or garbage collection. Thus far, I’ve been doing most of my development and testing using Xcode 4.3 running on OS X 10.7, but I wanted to start to do more thorough testing on 10.6. ARC is supported on both versions of OS X (though with a few minor restrictions on 10.6), but as I quickly discovered when I tried building my application with Xcode 4.2 on 10.6, building an ARC application requires linking against the 10.7 SDK, which is only possible if you’re running Xcode on 10.7. So while I can run the app fine on 10.6, not being able to build on 10.6 makes it a little tricky to use Xcode’s debugger to debug the application.

    After a couple days of searching and experimenting, I think I’ve finally come up with a setup that lets me debug my application relatively easily on 10.6 while still using ARC, and I figured I’d document it here. In my particular case, I’m running 10.7 on my main machine, then using VMware Fusion 4 to run an instance of 10.6 in a virtual machine, but the setup explained here should work just as well with two machines connected on a network.

    Workspace setup

    The first step in the process is to get things set up so that you can run your application from within Xcode 4.2 on your 10.6 machine. To access the application that is built on the 10.7 machine, I used standard file sharing in the Finder to connect from one machine to the other (I initially tried using VMware’s folder sharing feature, but it turned out to have some weird quirks and not work correctly a lot of the time).

    I wanted to open my Xcode workspace file in Xcode 4.2, but I figured that directly using the same workspace file that was being used by Xcode 4.3 on the other machine might not be the best idea, in case one saved changes under the other one’s nose, so I created a separate copy of the workspace (still one project file though) and opened that in Xcode 4.2. Later on, when I discovered I didn’t need to still have Xcode 4.3 running on my 10.7 machine (more on that later), this step turned out not to be necessary, but if you do want to have both versions of Xcode running at the same time, it’s probably best to avoid having them confuse each other.

    Since we don’t want to actually build anything in Xcode 4.2, use the “New Scheme” command and create a scheme with its target set to “None”, so no building will take place when using that scheme. Once the scheme is created, edit the scheme, and click on the “Run” action. Select “Other…” from the Executable pop-up menu, then go and select the built application that’s residing on your 10.7 machine. It’ll be hidden away in the Xcode “DerivedData” folder, the default location being ~/Library/Developer/Xcode/DerivedData. Once that’s set up, clicking the “Run” button with that scheme active should run the application from within Xcode.

    Debugging symbols

    You’ll notice when running the app that gdb spits out a whole bunch of messages to the console complaining about not being able to find various .o files. Normally, gdb looks here for debugging symbols that it uses to be able to display variables, stack traces, and other information while debugging. However, the .o files are referenced by absolute path when built, so when that information is stored on the 10.7 machine but being accessed from the 10.6 machine, the paths are different, so gdb is unable to find those files.

    The solution to this is fortunately pretty easy. In Xcode on the 10.7 machine, bring up the build settings for your application target, find the “Debug Information Format” setting, and change it to “DWARF with dSYM File”. This will cause a separate .dSYM file to be generated alongside your application when built, which contains all the debug information in one place and doesn’t depend on absolute paths. When running the app on 10.6, Xcode should be able to pick up the debugging info it needs from the dSYM file.

    Source Code

    We’re now able to debug the application, but if we hit a breakpoint, Xcode shows us a disassembly of our code rather than the actual source code. This is a similar problem to above, where gdb is looking for the source code files using absolute paths, but the paths are now different when running on the 10.6 machine. The best workaround I’ve found for this is the gdb command “set pathname-substitutions”, which basically allows you to tell gdb to treat any file paths starting with a particular prefix as though they started with a different prefix.

    So in our case, you would want to run “set pathname-substitutions /path/to/source/on/10.7/machine /path/to/source/on/10.6/machine”, of course putting in whatever the paths are on your particular setup. Since I didn’t want to have to type this in manually every time we start a new gdb session, I decided to create a .gdbinit file in my home directly and add the command there. gdb will automatically execute commands in that file whenever it starts, so that automates getting the source files to show up.

    Automating the build

    I had things pretty well set up at this point, where I could switch over to Xcode 4.3, edit and build my project, then go back to Xcode 4.2 and debug the newly built application from there. This quickly got tiring though, so I looked for some way to automate this process as well.

    I did this by taking advantage of the “pre-actions” provided by Xcode when setting up a scheme. This lets you specify an arbitrary script that should be run before running your executable each time. To set one up, select “Edit Scheme” from the Product menu, click on the disclosure triangle next to the “Run” action in the scheme editor, then click on the “Pre-actions” item that’s revealed. Click the “+” button at the bottom and select “New Run Script Action” from the pop-up menu.

    The actual building can be done using the xcodebuild command line tool, but of course the tricky part is that we want that to be done on the remote 10.7 machine instead of the 10.6 machine the script is being run from. Fortunately, this can be done pretty easily through ssh, so your script would look something like:

    ssh username@lion-machine-name.local “xcodebuild -workspace ‘/path/to/my.xcworkspace’ -scheme ‘My Scheme’ -configuration ‘Debug’ build”

    You’ll need to have ssh set up so you can connect using a public/private key pair, because otherwise the script will prompt you to enter your password to log in to the remote machine and just hang there. If you need to set this up, just search the web for “ssh keys howto” and you’ll be given plenty of guides on setting ssh up.

    So, now that that’s set up, clicking the “Run” button in Xcode 4.2 will fire off a build on the 10.7 machine, then when it’s done, run the newly built product on the 10.6, all ready for debugging! The only thing I haven’t figured out yet is how to tell when a build error occurs on the remote machine, so you sometimes still do have to switch back over to the Lion machine and build manually in Xcode 4.3 there if you want to see the details of the build error.

    Quirks

    I have run into a couple quirks with this setup still. If I have the project open in both Xcode 4.2 and 4.3 at the same time, sometimes both copies of Xcode got into some weird indexing loop, where one will start indexing, and somehow that will trigger the other copy to reindex files on its end, and so forth in a never ending loop. I’m still not quite sure why this was happening, since each one has its own indexing data stored within each machine’s home folder, but if this happens to you, you’ll probably just need to quit one of the two copies of Xcode.

    Occasionally, when attempting to run the app, I’ll get an error message from dyld saying that it couldn’t find one of the frameworks that’s embeddde inside the app bundle. The framework is indeed there though, so I’m not quite sure why this happens. I assume it must be some odd networking quirk running the app via file sharing. Usually either just trying a few times, rebuilding the app again, or poking at the build folder in the Finder will clear things up. I might investigate putting some “touch” commands in my pre-run script to see if that cuts down on instances of this.

     

  8. A new blog for a new day… or something

    This is the inaugural post of this new blog, wherein I talk about how I’ve never been good at blogging regularly in the past, but this time I’m actually gonna post stuff, for reals. I know this, because I think I’ve written this post two or three times before over the years. But for reals this time!

    I have posted the occasional developer/opinion piece on my blog over at my company blog at Fat Cat Software, but I think I’d like to keep that blog for just company related topics, with other stuff going over here. Dunno yet what I’ll post, but setting up the blog is the first step, so we’ll see how things go.