I ran into an odd issue the other day and spent a little time getting to the bottom of it. It turns out I wasn’t taking good care of my Xcode project’s library search paths. Here’s what I had to do about it and why you might care. Note this problem has likely been lurking in my project for some months, and may have caused other unintended consequences.
I was in the middle of updating a project with the latest AdWhirl and Millennial Media SDKs. If you are not familiar, the AdWhirl SDK uses the Millennial Media SDK and both have been changed recently to use a newer method in the MMAdView class. This ended up causing a runtime error, followed by a helpful stacktrace:
2011-05-10 17:11:43.105 reMovemFree[1630:707] +[MMAdView adWithFrame:type:apid:delegate:loadAd:startTimer:]: unrecognized selector sent to class 0x118c48
2011-05-10 17:11:43.184 reMovemFree[1630:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[MMAdView adWithFrame:type:apid:delegate:loadAd:startTimer:]: unrecognized selector sent to class 0x118c48'
I puzzled over this for a few hours trying to figure out just why this happened. The headers files were correct, and obviously the project was linking without a problem. At this point I didn’t want to write any more debugging or introspection code, but I was really just looking for a way to find out exactly which methods the class did support. That turned out to be a dead-end anyway.†
If you work with 3rd-party SDKs you might be accustomed to taking updates every few months or so. After some time you have probably updated certain libraries many times. I know I do this quite often. Many of you are probably way ahead of me here and can see where this is going. When you (literally) drop in a new SDK, and delete the old one, Xcode adds the new SDK path to the Library Search Paths for the project. Which is fine:
The problem is that Xcode didn’t delete the old SDK from the search paths when I dragged it out of the project. Since the build links with the first version of a library it finds on the search paths, any older version will usually do. Here’s what happens after repeatedly dropping in new versions of SDKs:
So what really happened was that I was linking to the earlier version 4.1.0 of the Millennial Media SDK, not the latest 4.2.4, even though both were on the library search path. This seems like a deficiency in Xcode, since it appears to go to lengths to track external referenced file dependencies.
The simple solution for me was to go in and manually prune the old SDK paths from the Library Search Path setting for my project. And of course, add a note in my “todo” list for future updates to take care when adding new SDKs. Unfortunately the Xcode 4 widget for editing the Library Search Path setting is a little funky compared to the Xcode 3 version. I managed to get it shrunk down so small it is barely usable, but with a great deal of patience I was able to find and zap the offending entries.
Incidentally, you may want to take advantage of Xcode’s Source Trees preference, which lets you define an external folder, give it a symbolic name, and refer to in inside your project. This is super handy for two reasons, 1) it dramatically shortens all the nearly-unreadable $(SDKROOT)/../../../etc paths, and 2) it makes code portability to different machines with different folder structures much easier. It turns this:
Hope this helps a little, even if just to remind you to double-check those Library Search Path settings next time you drop in a new replacement library from a 3rd-party vendor. If you know of a better way to manage this issue, I’d love to hear about it.
† The commandline tool “otool” is great for examining dynamic and static libraries. The problem for me was that I examined the libraries I assumed were linking, not the ones that were actually linking. Looking at the wrong library didn’t help, since it obviously had the right method signatures: