Posts Tagged ‘xcode’

Make Xcode nag you about unfinished TODOs

Friday, January 8th, 2010

If you’re like me, you often make promises to yourself in the form of TODO comments in your code. For example:

// TODO: make sure file exists before opening!
fooBar = [[FooBar alloc] initWithFile:path];

This is a reasonable thing to do, because sometimes you just want to get something working right now and aren’t in the mood to write all the required error checking code. But, you also know that you cannot trust your soft human brain to remember to add the check later, so you write a comment to remind yourself to do it.

Xcode recognizes the TODO: keyword in your comments and helpfully adds items to the function popup menu so that you can quickly navigate to them. In addition to TODO:, Xcode will also recognize FIXME: (when you know the code is broken), ???: (when you don’t know what it does), and !!!: (when you wish you didn’t know).

That’s helpful when you’re editing a file, but what about a TODO tucked away in some dark corner of your source code that you haven’t visited in a while? You’re likely to forget about it, and how can you keep a promise you forgot that you made?

The answer, of course, is to have somebody nag you. Fortunately, there’s a way to have Xcode fill that role. All you have to do is add a simple Run Script Build Phase which turns them into Build Warnings.

Select Project > New Build Phase > New Run Script Build Phase from the menu bar. Then, copy and paste this into the script window:

1
2
3
4
KEYWORDS="TODO:|FIXME:|\?\?\?:|\!\!\!:"
find ${SRCROOT} \( -name "*.h" -or -name "*.m" \) -print0 | \
    xargs -0 egrep --with-filename --line-number --only-matching "($KEYWORDS).*\$" | \
    perl -p -e "s/($KEYWORDS)/ warning: \$1/"

What does it mean?

Line 1 defines the keywords we want to search for. If you want to exclude a keyword or include a different one, edit this line.

Line 2 uses the find command to generate a list of all files in your project directory (SRCROOT) having an .h or .m extension. If you want to search more files, you will need to edit this line.

Line 3 uses xargs to pass those file names along to egrep, which searches inside the files for lines containing one of the keywords. If any are found, it outputs the file name, line number, and the matching part of the line.

Line 4 uses Perl to format the lines as warnings.

The output of the script will look like this:

/Users/benzado/Projects/FooBart/Baz.m:42: warning: TODO: make sure file exists before opening!

Xcode will recognize lines in this format and treat them as first class build warnings. You can see them in the Build Results panel and, just like a warning from the compiler, a double click will open an editor window and take you directly to the offending line.

An Exercise For The Enterprising Reader: modify the script so that no warnings or errors are reported during Debug builds, but TODOs are flagged as errors in Release builds.

Avoid defining your iPhone app’s default values in two places

Tuesday, October 6th, 2009

This is a guide to using XSLT to extract default values from your iPhone app’s Settings bundle into a separate property list file. That file can be loaded by your app at runtime, sparing you the need to maintain the same data in two places and avoiding the risk of a mismatch leading to buggy behavior.

(more…)

Show Xcode where to find Subversion 1.5

Friday, November 21st, 2008

I installed Subversion 1.5 using MacPorts (with the Porticus front-end), which places libraries in /opt/local/lib by default.  Xcode 3.1.1 supports Subversion 1.5, but it only looks in /usr/lib, so even though I have Subversion 1.5 installed, it claims my working copies are incompatible.  How did I fix this?

  1. sudo -s
  2. cd /usr/lib
  3. tar cvf oldapr+svnlib.tar libapr* libsvn*
  4. bzip2 oldapr+svnlib.tar
  5. rm libapr* libsvn*
  6. cd /opt/local/lib
  7. for NAME in libapr*.dylib; do ln -s /opt/local/lib/$NAME /usr/lib/$NAME; done
  8. for NAME in libsvn*.dylib; do ln -s /opt/local/lib/$NAME /usr/lib/$NAME; done
  9. exit
Lines 3-4 generate a backup archive.  In case something goes wrong, you can delete the libapr* and libsvn* files from /usr/lib and unpack oldapr+svnlib.tar.bz2 to go back to the way things were.

Line 5 removes the existing subversion libraries and lines 6-8 put symlinks in /usr/lib that point to /opt/local/lib.  Note that the set of libraries may not match exactly.  (In my case, some libraries for Python and Ruby bindings didn’t appear in /opt/local/lib.)  However, I figure it’s better to keep the set consistent than to piece together possibly incompatible parts.