Rss

Archives for : xcode

RxNot

A few weeks back, I tweeted:


The stealth message here was that there’d been a mass layoff, and as such, I’m no longer at MathElf. (Aside: which means, for the moment at least, I’m available for contract work: cadamson@subfurther.com).

While I’m not about to slam my ex-employer, I do want to get in a word about a key technology we used that left me cold. As the tweet indicates, this is gonna be about RxSwift.

Continue Reading >>

Let It Snow

I’m not the first to say this. Chances are you saw Marco Arment tweeting about it earlier in the week:

The latter half of 2014 has been a disaster in terms of quality of Apple software. As I was finishing up the book, I kept an index card of all the bugs I needed to file. I ran out of room.

List of bugs to file

Some of these have caused real pain, such as the Xcode 6.1 iOS Simulator not supporting internationalization — horrible for us when the third chapter of our iOS 8 SDK Development book walks through an i18n example, and a later chapter shows how to make a third-party keyboard extension, which doesn’t work because the simulator now only supports the US English and emoji keyboards.

Continue Reading >>

Social Swift Style Survey #1

So, Xcode 6 beta 7 came out today, and with it, lots of changes to the Swift APIs for iOS and OS X. Mostly, it’s the ongoing removal of the ! character from parameters and return types. The bang is an implicitly-unwrapped optional, meaning it’s an optional — a variable that may or may not have a value at all — but since having to check lots of variables against nil and unwrap them would be burdensome, you’re allowed to treat it like a normal non-optional variable. Only downside is that your app crashes if you don’t unwrap and it turns out to be nil.

In the early Xcode 6 betas, nearly every parameter in Apple APIs was a bang, since they had to be optionals (nils were commonplace in Objective-C), but Swift adoption would have been hindered if we’d spent June through August unwrapping them.

For the last few betas, Apple engineers have been doing yeoman’s work, going through all these APIs and identifying what must be an optional, and what doesn’t need to be. So, the bangs are disappearing, replaced by either ? for honest-to-goodness optionals that should be tested against nil, or empty space, indicating the variable will always have a value.

If you’re writing a lot of Swift code — say, for a beginner’s book with 30+ versions of your sample code app — you’re used to each new build breaking your code, and forcing you to do through and make some pretty simple edits to deal with API changes as the bangs disappear.

Swift compiler errors caused by removal of implicitly-unwrapped optionals in Xcode betas

In some cases, it’s making me do unwraps where I’d previously been playing fast and loose with the bang-type. And that brings me to a question. There are two ways to do unwraps, and I’m not exactly in love with either of them.

Here are two examples. In beta 7, all the UIViewController properties for finding parent containers (navigationController, splitViewController, tabBarController) have all become full-on optionals, so a reference to self.splitViewController.delegate no longer works. One way to deal with this is to explicitly test for nil, and then use the bang operator to unwrap inside the if block.


if self.splitViewController != nil {
    self.splitViewController!.delegate = self
}

This is OK, except that when you have a non-trivial number of lines in the block, all the bangs seem dirty. We can avoid this with option #2: casting to a non-optional type in the if:


if let validSplitViewController = self.splitViewController {
    validSplitViewController.delegate = self
}

Fewer bangs, but now I’m burdened with coming up with a name for the non-optional version of the variable. And good variable names are hard to come up with. Heck, what’s even a good convention for this? validFoo? unwrappedFoo? safeFoo? It feels like I’m polluting my code with more variables to keep track of.

Since I’m not pair-programming or working with a lot of people producing Swift code, I’m not sure which is becoming the preferred idiom, and I don’t want to inadvertently write a book of my own idiosyncratic coding style.

Next best thing… a poll! Let me know what you think, and I’ll ack back at some point with the results.

[iframe src=”https://docs.google.com/forms/d/1YD2bQ4-KUJzZzB2nkKqu2TsCedVIlC8Viqwrys04TME/viewform?embedded=true” width=”500″ height=”400″ frameborder=”0″ marginheight=”0″ marginwidth=”0″ Loading…]

Thanks in advance for your votes, comments, and pre-orders.

RESULTS UPDATE (Sept. 5): After a couple days and 38 votes, results are:

  • 26 votes for Use if let / if var to unwrap to a new variable
  • 5 votes for Test against nil, unwrap with !
  • 7 write-ins, almost all for an optional-chaining alternative I failed to mention: self.splitViewController?.delegate = self

Asynchronous Unit Testing in Swift: The Good, Ugly The Bad, And The

Janie Clayton-Hasz and I are working on the unit testing chapter for the still-unannounced book, and we’ve had enough fun that we decided to share a little bit of what we’re up to.

In the previous edition, I wrote a testing chapter based on Bill’s iCloud recipes project, and it was a nightmare for a couple of reasons. First, a completion handler that was supposed to be called from -[UIDocument closeWithCompletionHandler:] wasn’t, at least not in iOS 6. Second, iCloud sucks (c.f., “First”). And finally, the whole idea of testing something that takes an unknown amount of time is an interesting problem, one that OCUnit was not built to handle.

So it was really cool that Janie did the research and came back with promising results about asynchronous unit testing in iOS 8 / Xcode 6. Then we jumped into the chapter and… well, it’s not as pretty as the WWDC video would have you believe. It works, but sometimes you have to play a little dirty to get it there.

Continue Reading >>

The Audio Tools for Xcode 4.3 switcharoo

It’s great that Xcode 4.3 packs all the SDKs and essential helper apps into its own app bundle, which makes Mac App Store distribution more practical and elegant, and brings Apple into compliance with its own rules for MAS distribution. Adapting Xcode into this form is also a prerequisite for eventually delivering an iPad version, which I continue to believe is one of those things that may be impossible in the near-term and inevitable in the long-term.

However, this radical realignment means Xcode 4.3 has surely broken something in every Mac and iOS programming book. Lucky for me that mine are still in the works, though very close to being done. I updated the “Getting Started” material in iOS SDK Development this week to handle the changed install process, which along with the new chapter on testing and debugging should be going out to beta readers Real Soon Now.

And then there’s Learning Core Audio, where the situation is a little more involved. For one thing, the Core Audio book is content-complete and copy-edited, and we are now in the layout stage, with dead-tree edition just weeks away. In fact, I have to finish going over the layouts for the last half of the book by Friday, something I’m doing with iAnnotate PDF on the iPad:

20120226-155512.jpg

So this is the wrong time to be making changes, since we can only fix typos or (maybe) add footnotes. And that’s a problem because while Xcode 4.3 includes Core Audio itself in the OS X and iOS SDKs, it doesn’t include the extras anymore. And that breaks some of our examples.

This doesn’t hit us until chapter 8, where we create an audio pass-through app for OS X. This requires using the CARingBuffer, a C++ class that was already a problem because many versions of Xcode ship a broken version that needs to be replaced with an optional download. CARingBuffer lives as part of Core Audio’s “Public Utility” classes in /Developer/Extras/CoreAudio/PublicUtility.

At least it did, until Xcode 4.3. Now that there’s no installer, there’s not necessarily a /Developer directory. Well, there is, but it lives inside the app bundle at Xcode.app/Developer, and includes only some of its previous contents. For the rest, we have to use the “More Developer Tools…” menu item, which takes us to Apple’s site and some optional downloads:

Xcode 4.3 downloads page: Audio Tools

This lets us download the optional Core Audio bits as a .dmg file, the contents of which look like this:

Contents of Audio Tools .dmg

So there’s our CoreAudio/PublicUtility folder, along with the AULab and HALLab applications that used to live at /Developer/Applications/Audio. We use AULab in chapter 12 to create an AUSampler preset that we can play with MIDI, but apps can live anywhere, so this isn’t a real big problem.

PublicUtility does pose an interesting problem, though: where does it go? The code example needs the source file to build, and up to this point, we’ve used an SDK-relative path, which means that the project can’t build anymore, since it won’t find PublicUtility along that path, since the SDK itself is now inside of Xcode’s code bundle. So where can we put PublicUtility where projects can find it? A couple options spring to mind:

  1. Leave the path as-is and move PublicUtility into the Xcode app bundle. Kind of nifty, but I have zero confidence that the MAS’ new incremental upgrade process won’t clobber it. And an old-fashioned download of the full Xcode.app surely would.
  2. Re-create the old /Developer directory and put PublicUtility at its previous path. This requires changing the project to use an absolute path instead of an SDK-relative one, but /Developer is a reasonable choice for a path on other people’s machines. It suited Apple all these years after all.
  3. Forget installing PublicUtility at a consistent location and just add the needed classes to the project itself. Probably the least fragile choice in terms of builds, but means that readers might miss out on future updates to the Audio Tools download.

In the end, I chose option #2, in part because it also works for those happy souls who have not had to upgrade to Lion and thus are still on Xcode 4.2, still with a /Developer directory. There is, however, a danger that future Xcode updates will see this as a legacy directory that should be deleted, so maybe this isn’t the right answer. A thread on coreaudio-api on where to put PublicUtility hasn’t garnered any followups, so we could be a long way from consensus or best practices on where to put this folder.

For now, that’s how I’m going to handle the problem in the book’s downloadable code. This afternoon, I ran every project on Xcode 4.3, changed the paths to CARingBuffer in the one example where it’s used, and bundled it all up in a new sample code zip, learning-core-audio-xcode4-projects-feb-26-2012.zip. That will probably be the version we put up on the book’s official page once Pearson is ready for us.

Now I just have to figure out how to address this mess in a footnote or other change that doesn’t alter the layout too badly.

Achievement Unlocked: Finish “Learning Core Audio”

There’s nothing like losing your editor — to Apple, no less — to ratchet up the heat to finish a book that has been too long on the burner. But with Chuck doing exactly that at the end of December, Kevin and I had the motivation to push aside our clients and other commitments long enough to finally finish the Learning Core Audio book (yes, the title is new), and send it off to the production process.

In our final push, we went through the tech review comments and reported errata — Lion broke a lot of our example code — and ended up rewriting every example in the book as Xcode 4 projects, moving the base SDK to Snow Leopard, which allowed us to ditch all the old Component Manager dependencies. For the iOS chapter, we rev’ed up to iOS 4 as a baseline and tested against iOS 5.

One of the advantages of Xcode 4 is that the source directory is cleaner for source control (no more ever-changing build folder that you have to avoid committing), while also offering a pretty simple way to get to the “derived data” folder with the build result, which was important for us because we have a number of command-line examples that create audio files relative to the executable, and Xcode 4 makes them easy to find.

In our final push, we also managed to get in an exercise with the AUSampler, the MIDI instrument that pitch-shifts the audio file of your choice, into the wrap-up chapter. So that should keep things nice and fresh. Thanks to Apple for finally providing public guidance on how to get the .aupreset file to load into the audio unit, and how the unit deals with absolute paths to the sample audio in the app bundle case.

Updated code is available from my Dropbox: learning-core-audio-xcode4-projects-jan-03-2012.zip

From here, Pearson will take a few months to layout the book, run it by us for proofing and fixes, and send it off to the printer. So… paper copies probably sometime in Spring. The whole book — minus this last round of corrections — is already on Safari Books Online, and will be updated as it goes through Pearson’s production process.

It seems like there’s been a big uptake in Core Audio in the last year or two. More importantly, we’ve moved from people struggling through the basics of Audio Queues for simple file playback (back in iPhone OS 2.0 when Core Audio was the only game in town for media) and now we see a lot of questions about pushing into interesting uses of mixing, effects, digital signal processing, etc. Enough people have gotten sufficiently unblocked that there’s neat stuff going on in this area, and we’re fortunate to be part of it.

What Xcode 4 gets right (and Lion doesn’t)

It’s been a busy year for Apple user outrage, with radical changes to Xcode 4 and Final Cut Pro X provoking serious anger and lots of bitter denunciations on forums, blogs, Twitter and the like.

I can’t speak for Final Cut Pro X (I have yet to get my video hardware up to snuff), but frankly, I think Mac OS X 10.7 (Lion) deserves a lot more hate than Xcode 4.

And I’m happy to provide it.

Both have bugs, and with massive development, that’s not that surprising. I crash Xcode every few days. I get the spinning pinwheel of death from Lion every couple hours, in situations where it never occurred in Snow Leopard or earlier OS X releases. These will get smoothed out in time.

But once they are, what remains? Let me state my premise clearly: I like Xcode 4 because it’s built atop some fundamentally good ideas, and I dislike Lion because it’s not.

Let’s start with Xcode 4. Being on Lion, I can’t run Xcode 3 to reacquaint myself with the old days, but a few screenshots reminded me of some of its traits.

Xcode 3’s main window had a “Groups and Files” list on the left side. Except it didn’t have just files and groups of them. It also had an icon to represent your source code repository. And your recent searches. And smart searches. And bookmarks. And… you get the idea.

And that was before iPhone. Now Xcode had to handle provisioning, device management, remote debugging, archiving, and so on. iPhone development made demands that Xcode wasn’t really meant to handle, and it’s clear that iOS is going to be more and more important in the future, meaning that Xcode needs to be at least as aligned to iOS development as Mac, if not more so.

And this, to me, is what Xcode 4 gets right: it is a fundamental rethink of Xcode, informed by the first few years of iOS development. Its changes are radical, but in general, they’re based on cohesive and sensible ideas.

The biggest change in Xcode is how responsibilities are divvied up: the project workspace window is the container for anything related to a given project, and the organizer is for cross-project concerns like documentation, device management, source code repositories, and so on. Within the project workspace, there’s a fundamental left-to-right flow of specificity: a selection in the navigator sets the content area, and a selection in the content area can have further consequences in the utility area. That means we can pick files in the file navigator to bring them up in the source editor (the typical case), or use the log navigator to show build or runtime logs in the content area. The generic approach to the content area also opens up new opportunities: we already see this with Interface Builder incorporated as the editor for NIB files, and in Xcode 4.2, the content area offers up a new UI for editing storyboards.

Meanwhile, the now-prominent organizer makes the system of archiving builds more visible, which is critical not only because you now have to use this interface to submit to the App Store, but also because archiving is the only way to symbolicate and thereby make sense of crash logs you get back from Apple.

Quibble with specifics, or the roughness of a new codebase, but I do think Xcode 4 has its head in the right place. It’s built on fundamentally good, forward-looking decisions that put an end to the era in which Xcode frantically shoehorned in new iOS-related concepts, and is better positioned to adapt to whatever Apple throws at it over the next few years.

For a contrast, let’s look at Lion.

As with Xcode, I’ll set aside the annoying bugs — though I don’t know that I’ll ever forgive Lion’s Finder for losing the positioning of icons in most of my windows — and look at the ideas behind it.

What is the underlying concept of Lion? We’ve heard a lot about the importation of iPad features, notably the aggressive use of multi-touch gestures. The big one of these, of course, is the reversing of the scroll direction, dubiously spun as “natural” scrolling by Apple.

The problem with the iPad metaphors, for a start, is that there’s a fundamental difference between desktop and tablet gestures: desktop users are touching a proxy object like a magic mouse or trackpad. On the tablet, you can see the thing you’re touching; on the desktop, there’s a detach between the two.

In many ways, Lion seems optimized for laptops, which always have touchpads, and which enjoy a more intimate relationship with the user than a potentially sprawling desktop. As much as I hear the Mac Pro disk thrashing and see the aforementioned spinner, I also wonder if Lion isn’t really meant for use on machines with SSD storage instead of conventional hard disks.

And if Lion truly is optimized for portables, and if this is the reason for its seeming “iPad-ization”, I think it begs the question: why turn my Mac into an iPad, when I could just buy an iPad instead.

Honestly, I like my iPad. As I’ve said before, I like the iPad more than a laptop, and have gone iPad-only for my last few conferences. Thinking further ahead, the iPad is only going to get more powerful and more capable, while the traditional computer is fairly static in its abilities. Of all the things I need to do, the only productivity that’s really unavailable to me on the iPad is coding: there’s no Xcode for iPad, and it’s not clear whether a slimmed-down version would be possible with current hardware. But it’s not out of the question: Apple introduced Xcode in 2003, and the iPad 2 already outclasses a top of the line PowerBook of that era. In time, and probably not long from now, I’ll be able to do everything I care about on the iPad, and will be happy to.

So why compromise the desktop now, and turn it into something it’s not, which is to say a desktop OS with iPad features bolted on? Lion’s iPad-isms don’t really pay off for me, and what we’re left with is a mish-mash of incongruous concepts. Unlike Xcode 4, there’s no unifying concept behind Lion’s changes; instead, it feels like they’re trying to capture the iOS buzz and excitement, cramming in iPad-isms wherever they can be made to fit.

Steve Jobs famously made the analogy that desktop computers are like trucks, and that fewer and fewer people need trucks. It’s a clever and insightful analogy. The problem for me is that the people who need trucks don’t want those trucks turned into oversized sedans. What consistent ideas are present in Lion serve to work against what makes a desktop OS useful and productive in the first place.

The desktop OS doesn’t need a fundamental rethink; it may well be on a slow path to obsolesence, and it’s fine for Apple to let it go, as iOS is the heir apparent. But in lieu of a grand reinvention that is not likely, necessary, or needed, change for the sake of change is not welcome.

And don’t even get me started about the little things (monochrome icons in Finder sidebars, the hiding of ~/Library, Launchpad… must resist urge to hurt someone…)

Leaving the Laptop

Trying an experiment for next week’s WWDC: I’m leaving the laptop at home and taking just my iPad.

In part, this is motivated by my preference to max out and not compromise my computing environments. I’ve come to see laptops as inherently compromised: not as powerful as a desktop, not as portable as a tablet, but more expensive than either. So when I’m at my desk, I have an 8-core Mac Pro with gobs of RAM and four drive bays, and when I’m moving around, I have the one-pound iPad. Of course, there are trade-offs, but they don’t always matter: the MacPro, monitor and associated gear probably weighs 70 pounds… but it’s not going anywhere. The iPad isn’t exceptionally powerful, but it’s not like I’m authoring Blu-Ray discs with it.

The iPad has long since become my preferred means of checking web and e-mail around the house, and I’m trying to push what I can do with it in terms of productivity. As I’ve mentioned before, I wrote chapter 9 of Core Audio almost entirely on the iPad with Textastic and a dock keyboard. I even wrote a few functions for the code examples with Textastic, fixing them up once I got back to Xcode on the Mac.

So for the kinds of things I will need to do at WWDC, mostly note-taking and keeping up with mail, Twitter, Facebook, etc., the iPad is perfectly capable, and a fraction of the weight of a laptop. Plus, the iPad and dock keyboard will fit nicely in the small attaché case we got at WWDC 2008, meaning I don’t need my enormous JavaOne backpack for laptop, cables, and gear (I hated JavaOne as a conference, but I’ve gotten a lot of use out of their laptop-friendly backpacks).

I also need to work on my books, but as I’ve said above, I have a system for this. On my Mac, I’ve checked out the sources to Core Audio and the other one we’re not talking about yet into my Dropbox, so it’s easy enough to pull those files into Textastic, or any of the other Dropbox-based editors (iA Writer, the official Dropbox app, etc.). So as long as I remember to push my edits from the iPad back to Dropbox, and then svn commit from the Dropbox folder on the Mac, I’m good. Yes, direct Subversion and Git support in the iPad text editors would be preferable, but this will do.

Overall, the weird thing about trying to push productivity on iPad is the decision they made to hide the file system. It makes sense that 95% of files are opened only by a single application (if the user even “opens” them at all… consider browser bookmarks and mail messages), so it’s sensible to make that app own those files outright, and eliminate the need for a Finder. But that really does complicate the other 5% of cases, like when you want to post a picture to web page, or share files between applications. Whether you accept this depends, I think, on your ability to see the unseen: can you appreciate how much hassle the other apps save by not expecting you to serve as the wise, all-knowing administrator of a file system? Don’t you have parents or grandparents who don’t even know the difference between the home, Documents, and Desktop folders? We may not really know if this is the right paradigm until and unless we have kids who grow up primarily in a filesystem-free app-and-cloud world. But it does make a lot of sense when you think about it.

So what won’t I be able to do? It occurred to me that I can’t build code on the iPad, so that means I won’t get much use out of the WWDC labs. Or can I? The labs always have iMacs with Xcode, so it seems like I could put my projects into AirSharing on the iPad, then open them up from the lab iMacs. So that should be covered.

And I bet I’m not the only person who’s holding out some hope that Apple will actually bring Xcode to the iPad. They’ve brought over a number of their other marquee applications, and Xcode 4’s redesign into a single window makes it far more suitable for being adapted to iOS. It’s not at all hard to imagine some of the appearing/disappearing views like the inspector pane being implemented as popovers on an iPad. It would be a hell of a surprise this year, but in the long run… why not?

This Thing I Do!

It’s been an interesting couple months with all these versions of iOS. Until last week, most of us had to juggle one legacy version (3.x), a production version (4.0 or 4.1), and the important 4.2 beta, which ushered iPad into the modern age. If you’re working on code for production, you likely needed to focus on at least two of these, possibly all three.

The Xcode tools have a reasonable means of letting you do this, by installing to locations other than the default /Developer with a few caveats, such as that a single set of the System Tools and the UNIX stuff can be present on a volume, and must be in specific locations.

My standard is to put the legacy SDK (currently 3.2) at /Developer_Old, the current production release at /Developer, and the latest beta at /Developer_New. So far so good. But what happens when you double-click an .xcodeproj or .xib… which version do you get? Do you notice or care? Probably not until you find out that the target SDK in the project file is unsupported by the version you launched. And what if you run multiple copies at once… what version of IB or the Simulator is that on your dock?

After fooling myself one time too many, I adopted a system of changing the icons of the core tools to give myself a visual indication of which SDK I’m working with. This way, I can start a specific version of Xcode right from my dock:
Aliases to different versions of Xcode

Here’s a quick look at how you can set this up for yourself.

Basically, what you need to do is to create alternate versions of the .icns files of the apps you’re interested in. For me, that’s Xcode, Interface Builder, and the iOS Simulator. I’ve created two folders, in /Developer/Xcode and simulator icons to store these .icns files permanently.:

Futuristic versions of icons
Old-timey versions of icons

As you can see, I’ve got one folder called Futuristic for the icons for betas, and another called Old Timey for the legacy SDKs.

To make these icons, start by visiting an application’s installed location in the Finder:

  • Xcode – /Developer/Applications/Xcode.app
  • Interface Builder – /Developer/Applications/Interface Builder.app
  • iOS Simulator – /Developer/Platforms/iPhoneSimulator.platform/Developer/iOS Simulator.app

Now, peek into the application by right-clicking/ctrl-clicking the app and choosing “Show package contents”, then open the “Resources” folder. You need to find the appropriate .icns file:

  • Xcode – appicon.icns
  • Interface Builder – InterfaceBuilder_App.icns
  • iOS Simulator – simulator.icns

Don’t double-click the .icns; that will probably just open Preview. Instead, make a copy and use “Open With…” (via File menu or right-click/ctrl-click contextual menu) to open up Icon Composer.
Interface Builder icon in Icon Composer

This shows the icon at the various canned sizes: 512×512, 256×256, etc. Select one of these and copy with cmd-c.

Now open an image editor… I’ve used both Pixelmator and Acorn for this kind of stuff. You don’t have to buy Photoshop. For this blog, let’s assume you’re using Acorn. Over there, do “New from cilpboard” to create a new document of the image you’ve copied from the icon. Now choose an image effect that will colorize the icon in some meaningful way, without changing its size or shape. In my case, for the old-timey look of legacy SDKs, I applied the “Sepia Tone” effect:
Applying Sepia Tone effect to Interface Builder icon

And for the futuristic look to distinguish beta SDKs, I used the Quartz Composer “thermal camera” effect:
Interface Builder icon with thermal camera effect

Copy this image, close it, go back to Icon Composer, and paste it in. Repeat for all the other sizes. When finished, use “Save As…” to save the .icns file to some safe place (I use /Developer/Xcode and simulator icons).

Now, re-visit the legacy or beta applications whose icons you want to change, and option-drag your hacked .icns file into the Resources folder, replacing the default icon (you might want to do this on a copy of the application the first few times, just to make sure you’re doing it right).

Now, when you launch these apps, you’ll be able to tell immediately which is which in the Dock.
Three different versions of Xcode running side-by-side
You can also collect aliases to each version in a single folder, then put that in the Dock (as I did with Xcode in the first screenshot) for a one-stop shop to launch the version you need.

Work Song

It’s not like I don’t have better things to do, but on the verge of sending a build to testers, and knowing I would probably forget to update the version number sooner or later, I set about putting a build date into my Xcode project. And for fun, I did it one better.

First off, the build date is pretty easy. Open up your project’s targets and right-click to do an “Add → New Build Phase → New Run Script Build Phase”. Under the Target, you’ll see a gray box called “Run Script”. Drag this to the top of the list of build phases – we want to do this step first – and do a Cmd-I to bring up its inspector. By default, scripts run with /bin/sh, which is fine. For the script body, just enter:


date > builddate.txt

Do a build and inspect your project’s directory to verify that the builddate.txt file got created. It’ll look like this:


Tue Nov 24 10:29:31 EST 2009

Assuming the file got created, drag the file to the “Resources” folder in your project. This will add a new item to the “Copy Bundle Resources” build phase, which is exactly what you want: the script will create the file, and then the copy phase will copy the file to your bundle. You probably don’t want to source control builddate.txt, since it’ll be created as part of the build (of course, if you don’t, anyone who checks out your project will see those files in red, since they’re missing, until they kick off a build).

Now it’s easy in code to get the contents of this file into your GUI or wherever else you need it (in my case, this code is in the “about” view controller’s viewDidLoad:):


buildDateLabel.text = [NSString stringWithFormat:@ "Built on %@", 
	[NSString stringWithContentsOfFile:
		[[NSBundle mainBundle] pathForResource:@"builddate" ofType:@"txt"]
	encoding: NSUTF8StringEncoding error:nil]];

Oh, but that’s not enough. I decided it was necessary to also let my testers know what tunes they should be listening to. So I added the following AppleScript file (inspired by Erik Rasmussen’s) to the project:


set track_name to ""
set track_artist to ""
tell application "iTunes"
	try
		if not (exists current track) then return "(nothing playing)"
		set track_name to (get name of current track)
		set track_artist to (get artist of current track)
	end try
end tell
set build_tune to track_artist & " - " & track_name

The script’s return value is a string with the artist name and the song name, with a separator. If you call the script from the shell, it’s trivial to then dump the returned string into a file. So, create another Run Script Build Phase (you might want to rename these phases from the generic “Run Script”, BTW). This time, the script is:


/usr/bin/osascript iTunesTrackReader.scpt > itunestrack.txt

Again, drag this build phase before the Copy Bundle Resources phase. Once you’ve done a build, the itunestrack.txt file will exist, and you should copy it to the Resources folder, so it will get copied into your app bundle.

In the code, the “artist – song” string got a little wide on the phone, so I used a two-line label and replaced the separator with a new-line:


NSString *twoLineString = [[NSString stringWithContentsOfFile:
	[[NSBundle mainBundle] pathForResource:@"itunestrack" ofType:@"txt"]
	encoding: NSUTF8StringEncoding error:nil]
	stringByReplacingOccurrencesOfString: @" - " withString: @" -n"];
iTunesLabel.text = twoLineString;

And here’s the result (click for full-size):

Screen shot 2009-11-24 at 10.28.00 AM

OK, probably could have made better use of two hours, but it’s checked in now. Plus, it’s like an automated version-naming system: “are you running the “American Idiot” build or the “Kind of Blue” build?”