A while ago I forked my development endeavors my tackling iPhone development. Coming to it from an AS3 background made some parts easier than others to assimilate. One of the things in AS3 is that you could have packages of classes, etc. in a project, but if they were not imported or included into class files actually implementing them, they wouldn’t compile into the SWF(s). That appears to not be the case in development for the iPhone/Mac.
Recently I was debugging a project on 1st generation Touches. And everything was working perfectly. I then began debugging and developing on a 2nd generation Touch. This had a higher version of iOS because it could actually run it. 1st generation Touches have fallen back because they don’t have enough horses under the hood to properly power later advances in iOS.
I began playing with a screen mirroring class that I planned on using to show my application’s UI on a big panel using an iPad dock connector to VGA adapter. So I wrote up the class and there it sat in my Project. I implemented the class in my app delegate.
Later I decided that I wouldn’t need it. So I removed the class import statement in my app delegate’s .m file, and I removed the setup method from the didFinishLaunchingWithOptions method. I thought nothing of it and carried on thinking that class would now be free from future compiles.
I compiled my application back onto a test 1st generation Touch (which doesn’t supportUIScreenDidConnectNotification which is used in the screen mirroring class), and my application would crash with a
dyld: Symbol not found: _UIScreenDidConnectNotification
Referenced from: …/AppName.app/AppName
Expected in: /System/Library/Frameworks/UIKit.framework/UIKit
Hmmm. I removed the import and the method implementation. Did I need to clean the project because something was being cached? Tried that to no avail. Something was decidedly wrong. I googled the error and found a hit or two mentioning weak linking, etc. Tried that and obtained the same crashing results.
A quick jaunt over to the Apple Developer Forums was needed and I posted my problem there. After a bit of time I received my answer… category implementation. The fact that the class is in my project at all means it’s getting linked.
But what is a category? It’s an alternative to subclassing. You add methods to a class (remember the prototype days in AS2?) Any methods that are added to a class through a category become part of the class definition. Meaning ANY instance or subclass of the class will have access to the added methods. Cool, I hadn’t seen or knowingly run into this before. It’s great to know, but was kicking me squarely in the balls because of my naivete. Again, good to know and can be quite useful!
I pulled the class guts of the screen mirroring class from an open-source class online. And guess what? It was using a category for UIApplication.
@interface UIApplication (ScreenMirroring)
But still, the fact that I wasn’t importing the class at all made me assume that it wouldn’t be compiled into the Target. What I was told on the forum:
The source code that makes the offending reference to UIScreenDidConnectNotification is still being compiled because it’s in a file that’s part of your project.
Well… does this mean if you write a bunch of throw-away classes in your project that you’re not using, they still get compiled into your Target(s)? It would appear so and is a break from the mindset I’ve had in project development for a long time, coming from a heavy AS3 background. I use wildcard imports quite a bit in AS3.
I would consider this a gotcha. Perhaps something that those with a lot more Xcode experience would scoff at, but you could run into this situation as well. The fact that all the code in your project compiles is something I wasn’t aware of. Trim one’s projects.