Navigation

My Xcode 4 blocker of the moment

Tuesday, July 5th, 2011

My current set up in Xcode 3 runs something like this:

  • For day to day development, I use the Debug configuration. Pretty standard. No real correlation between running the product on the device and simulator.
  • When I want to do — or simply try out — a Release style build, I switch to the release configuration. I do this from time to time just as a sanity check. 99% of the time I use Release, it’s on the device.
  • Even more rarely — once a week at the maximum — I need to do a release. In my case, these releases are usually milestone builds for clients, just to show how the application is progressing.

Even still, I have a couple of requirements about these release builds:

Firstly, I need to be able to run and test the exact build I’m going to send to a client. Seems foolish to do anything else.

Also, I have a somewhat complicated, but I don’t think unreasonable release process. It goes something like this: After running and doing a final smoke test on the release build, I run a script I’ve developed. This script:

  1. Copies the dSYM from build/Release to dSYMs/
  2. Commits
  3. Adds a tag for the current version (based on the CFBundleVersion)
  4. Bumps the CFBundleVersion
  5. Commits
  6. Runs the PackageApplication script included with Xcode to create a .ipa file from the .app in build/Release
  7. Opens a Mail message with that .ipa file attached

It also has support for parsing & incrementing the CFBundleShortVersionString key and a couple other things.

So to be clear, I’m backing up the dSYMs for each release in source control and trusting my email provider to host the builds of old versions of the applications (only reason I’ve found to need those EXACT old versions is to re-sign them).

Also note that this script isn’t run from Xcode, and in fact it wouldn’t be a good idea to do that. (I’m working on a version that has interactive capabilities to prompt the user if it notices odd things, like if the build it finds is older than a certain threshold or signed in a way that’s probably wrong.)

I think these are all pretty reasonable requirements. It’s certainly not the most Xcode-y way of going about doing this, but it makes sense to me and I think is at least somewhat internally consistent.

Where Xcode 4 falls down

Firstly, the new default location for built products — which is in ~/Library/Developer/Xcode/DerivedData/$AppName-$RandomSeriesOfDigits1 and seems to have been chosen so schemes and workspaces don’t step on each other (totally reasonable) — totally breaks my script. I’m totally not against having to add more options to my script (plus some sensible defaults) for specifying which scheme or workspace or whatever is wanted, and then having my script look up the location for that scheme. But there doesn’t seem to be any way to do that.

(Moving my built products back into SRCROOT seems like it’s begging for disaster further down the road, and I’m really hesistant to do this.)

I also find the combination of schemes & actions totally unnecessary. I don’t understand what problem they’re trying to solve. I’ve never found configurations, especially with .xcconfig files, to be inadequate.

The default actions are both too limiting — in my workflow there are multiple types of “Archiving” (more on that word later) — and also way too broad — testing and analyzing and running are all totally overlapping for me. I also can’t imagine a workflow where I’d want to configure more than one of the actions for a particular scheme — that seems like something you’d want in a target. Maybe I’m missing something.

Aside: Core Data

One problem not mentioned above is Xcode 4’s handling of Core Data. All of the below applies to the only released version, 4.0.2.

  • You cannot change the model version identifier. rdar://problem/9592700 which is duped to rdar://problem/9006105 (which I see as open).
  • When you create a new model version, what you enterĀ for the model’s name in the into the wizard doesn’t stick. I.e. “MyApp (5) 2” is the default and no matter how many times I tried to change it to “MyApp (6)”, the resulting file would be created as “MyApp (5) 2”. Infuriating.

Returning to the main thrust of the post, about Xcode 4’s failings

Because of the above problems with Core Data, I still need to use Xcode 3 somewhat frequently — at the very least to deal with Core Data model files. It’s really unclear to me what exactly is going to propagate back from Xcode 4 in terms of schemes, actions, etc. Not creating an addition scheme seems to not break things for me, but I have not played with this out of fear of breaking it.

Finally, I’d like to address “archiving”. The standard archive action frankly blows for one big reason: I have multiple machines. It’s largely worthless to have half the dSYMs on one machine, half on the other. Moving the dSYMs into source control and keeping the .ipas in email is a pretty good solution and works well. Having to dick around in the Organizer is so annoying. (The Organizer itself seems to be a random collection of functionality the designers that weren’t iTunesy enough to fit in the main UI.)

This situation honestly sucks, and I see no way to use Xcode 4 for releasing software (especially when it involves Core Data) — for the foreseeable future I’ll continue to use Xcode 3 for doing so.

(One last thing: Xcode 4 is a total boor on a 13” screen. It’s nearly impossible for me to use comfortably. (If you tell me my font’s too big I will hurt you.))


  1. An example of this is: /Users/cbarrett/Library/Developer/Xcode/DerivedData/test-ghxwstqpgxzcuufqwfomddrxbuzo/Build/Products/Debug-iphonesimulator/test.app.dSYM 

Comments

  1. Steven Fisher replied on July 5th, 2011:

    Well, the 13” screen is definitely a concern. I’ve got one. I found it a bit better than Xcode 3.3, but that’s entirely subjective. Have seen hints that something is planned to make this far, far easier than 3.3 ever was. But no other comments on that. :)

    No argument on Core Data. I’m not using it yet, but everything I’ve seen on the subject agrees with you.

    But that said:

    Your scripting all sounds really doable with Xcode 4. (And I do NOT mean driven from Xcode, but rather driven from the shell.) I used to have a script that updates version numbers and built all the combinations I need, for instance. Xcode 4 does have the hooks to copy the files I need from the build folder to a more reasonable place, which your script could pick up on. I haven’t done this yet because I rarely add want to keep builds, and I’ve been copying files manually around for this since Xcode 3.2. The hooks to do this automatically are actually new in 4.0.

    Configurations and schemes are something I had problems with for a long time. Here’s how I came to understand it now: Schemes describe a group of common things you want to do. You can’t add or remove things, but you can change how each of the things works. Configurations are how the executables for these actions are built. If you wanted to, you could create a Debug and Release scheme. The Debug scheme could use the Debug configuration for everything. The Release scheme could use the Release configuration for everything. You could switch between the schemes just as easily as you could switch between configurations in Xcode 3.3. This would essentially give you Xcode 3.3 behaviour in Xcode 4.0. Using schemes well is much better than the old way.

    Even though you are stuck cooperating with people using Xcode 3.3, and I think you could write scripts that would handle both Xcode 3.3 and 4.0 at once. Add a post build script to your Xcode project to copy the builds and symbols from where they’re generated to within your source tree. Not the intermediaries, just the stuff you’re actually interested in. Modify your script to pick up the files from there instead of the Xcode 3.3 locations.

    When you want to move forward, ask questions and get answers. The most important thing to realize is this: There are answers.

  2. Jesper replied on July 6th, 2011:

    I agree with Steven. It sounds like you’re working against the grain. It appears to me that it’d be far easier to take over “Build and Archive” by defining your own actions to archive the way you like (1..5 in a pre-action, 7 in a post-action). You don’t have to keep the script entirely within Xcode, just call out to your own script with the right parameters. And why not use xcode-build to trigger the script and surrounding actions? Your final smoke test should have just finished running so it’ll just figure out in short order that everything’s up to date and work with the right files.

    In any case, getting wind of the build locations as long as you choose to store them inside the build folder in each project isn’t rocket science. It’s ./build/$buildconfiguration[-$deviceplatformtarget]. Where the location is when you store them in the derived data location, I don’t know, but Xcode 4 is AppleScriptable and you can go ask a workspace document for its current product directory. Also, the Internet! http://stackoverflow.com/questions/6098315/xcode4-reliably-detect-the-deriveddata-directory-of-a-project-workspace

    The way I solve screen real estate, besides having a bigger screen, is to make use of tabs to set up nice working conditions; one for IB work (inspector visible, navigator hidden), one for source editing (navigator hidden, assistant split) etc. I tried opening up an iPad storyboard document and even a 17” screen starts looking pretty titchy, so this problem probably won’t go away over time. At least you can zoom out there.

    The problem schemes are trying to solve is best described by Chris Espinosa in one of them Xcode 4 talks: he talks about how the Xcode 3 target/arch/platform/device/everything picker controls every single axis in the build matrix, but how only some of those combinations make sense. The idea behind a scheme is simply to have one for every combination that makes sense.

    Because you can build (or test) multiple targets per scheme, that “combination” doesn’t have to limit itself to one each per target. You don’t have to add phony targets to “build all”, just make a new scheme. (A good unorthodox example is xscreensaver, which has one target per screensaver; it could now have one scheme for the core code, one for the tester application and one for “build every screensaver”.)