views:

1008

answers:

3

I'm making a universal iPad/iPhone app which can use the iPad's VGA out connector to mirror the content of the app on an external screen. However, the iPhone does not have this functionality. given the following code,

#ifdef UI_USER_INTERFACE_IDIOM  
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    NSLog(@"this code should not execute on iphone");
[[NSNotificationCenter defaultCenter] addObserver:self
         selector:@selector(screenInfoNotificationReceieved:) 
          name:UIScreenDidConnectNotification
           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
         selector:@selector(screenInfoNotificationReceieved:) 
          name:UIScreenDidDisconnectNotification
           object:nil];
}
#endif

I get this error on the phone at launch (works fine in ipad) "dyld: Symbol not found: _UIScreenDidConnectNotification"

presumably because UIScreenDidConnectNotification doesnt' exist yet in 3.13. How do I check for this at runtime?

UPDATED added ifdef statements to check for ipad interface but getting the same result!

UPDATED added NSLog statement to make sure the code inside the if statement is not being called. The crash seems to occur before any other code is executed...

+1  A: 

Follow the "Programmatically Determining Device" section at http://iphonedevelopment.blogspot.com/2010/04/converting-iphone-apps-to-universal.html

plus

#ifndef __IPHONE_3_2 // if iPhoneOS is 3.2 or greater then __IPHONE_3_2 will be defined
  typedef enum { // provided by noblemaster ]:-|
    UIUserInterfaceIdiomPhone, // iPhone and iPod touch style UI
    UIUserInterfaceIdiomPad, // iPad style UI
  } UIUserInterfaceIdiom;
  #define UI_USER_INTERFACE_IDIOM() (([[UIDevice currentDevice].model rangeOfString:@"iPad"].location != NSNotFound) ? UIUserInterfaceIdiomPad : UIUserInterfaceIdiomPhone)
#endif // ifndef __IPHONE_3_2 

in the comments section.

ohho
it's weird but that doesn't seem to work. it works for other stuff- (I'm using the UI_USER_INTERFACE_IDIOM in other parts of the code to successfully perform conditional compiles) but when I add it here I get the same problem, it still complains about UIScreenDidConnectNotification not being defined. at runtime- this is not a compiler warning.
joshue
FYI, I copied and pasted your code segment in my 3.2 project and runs fine in the simulator. weird ...
ohho
thanks for testing Horace, is your project set up as a universal app? my simulator works fine because it's simulating an ipad: I'm having this problem when running on a 3gs- ipad works fine...
joshue
try put some NSLog inside the #ifdef UI_USER_INTERFACE_IDIOM to prove you have excluded the 3.2 code from iPhone correctly ;-)
ohho
I added NSLog statement right after the idiom check, it's not getting called. It looks like the crash occurs at launch, with no other code executing before the crash...
joshue
+2  A: 

Try weak link UIKit. Add into your other link flags:

-all_load -ObjC -weak_framework UIKit

If you target pre-3.1 devices but refer to a class which only exists in 3.2, you can't refer to them by symbol, you have to use NSClassFromString. But there are cases where this isn't possible, e.g. if you subclass such a class (say UIPopoverController). In those cases you have to weak-link UIKit. When you weak-link a framework, the dynamic loader attempts to resolve all the symbols on startup, if it fails, it's set to NULL.

I'm guessing the constant UIScreenDidConnectNotification isn't tagged (bug), so you need to use the same workaround.

There is a downside to weak-linking. Since it has to do this upon startup, dynamically, startup time takes a hit. You'll have to test if it is too slow for you.

Another way to weak link a frame is: do "Get Info" on your target and under the General tab, you will see the list of frameworks. Change the type for UIKit to Weak.

BTW, using a #ifdef to check doesn't work, because #ifdef are compile-time constructs, so UI_USER_INTERFACE_IDIOM will always be defined because you are building using the 3.2 SDK

Hwee-Boon Yar
this works! I added that line to my "Other Linker Flags" line in the linking dialog (is that the right place?)- can you tell me what this is doing and why it works? will it affect anything else in the app?
joshue
thanks for the clarification... in this case it doesn't seem to impact startup time too badly- and I agree- I think this is a bug (that UIScreenDidConnectNotification isn't tagged).
joshue
A: 

Another way to weak link a frame is: do "Get Info" on your target and under the General tab, you will see the list of frameworks. Change the type for UIKit to Weak.

That worked for me for the issue "Symbol not found: _UIScreenDidConnectNotification" on iPhone at runtime.

Roger Theriault