joshue
joshue

Reputation: 203

iPhone check for a constant at runtime in universal app

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...

Upvotes: 5

Views: 3266

Answers (4)

Jesse Clark
Jesse Clark

Reputation: 1200

From Elfred's answer to related question: How to test for the existance of a constant when creating a iPhone universal binary

if (NULL != &UIBackgroundTaskInvalid) {
   //do multitasking stuff here
} else {
   // don't do multitasking stuff here.
}

Upvotes: 1

Roger Theriault
Roger Theriault

Reputation: 1

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.

Upvotes: 0

Hwee-Boon Yar
Hwee-Boon Yar

Reputation: 512

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

Upvotes: 3

ohho
ohho

Reputation: 51921

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.

Upvotes: 0

Related Questions