I'm trying to check with Preprocessor-Ifs if the Device is an iPad. If it is an iPad, I want to define something Devicespecific, but for some reason I can't check in an PP-IF if a PP-Constant is true.
Maybe you got an idea?
#ifdef UI_USER_INTERFACE_IDIOM
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#else
#define IS_IPAD false
#endif
#if IS_IPAD
#define WIDTH 768
#define HEIGHT 1024
#else
#define WIDTH 320
#define HEIGHT 480
#endif
Preprocessor rules are, (surprise, surprise) processed prior to building the app. Since it's an universal app, it doesn't yet know if it's running on an iPad or an iPhone.
Use this:
#ifdef UI_USER_INTERFACE_IDIOM
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#else
#define IS_IPAD false
#endif
#define WIDTH (IS_IPAD ? 768 : 320)
#define HEIGHT (IS_IPAD ? 1024 : 480)
This is my approach: you can use this in the header file
#define _IPAD ((__IPHONE_OS_VERSION_MAX_ALLOWED >= 30200) && (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad))
#define GUI_TITLE_LABEL_WIDTH (_IPAD? 220*2 : 220)
#define UI_FONT_SIZE (_IPAD? 20 : 16)
Short and easy :D
You have a runtime check inside of a #if statement. A preprocessor check will not evaluate (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) so the width and height will have to be set at runtime since you can not tell if it is an iPad until runtime. I would also recommend using 0 instead of false.
(When you ask a question on SO, you should tell what you tried, and what happened.)
Anyway, I think you will not be able to do what you want there, because at compile time, the compiler does not know what device you will be running on. You could compile the code, and then run on an iPad, and iPhone, an iPod - how could the pre-processor possibly know which device you will be running on in the future?
Related
//initial code:
#define MYDEBUG YES
#if (defined(MYDEBUG) && MYDEBUG == YES)
#define NATIVEUNITID #"unitid_debug"
#else
#define NATIVEUNITID #"unitid_release"
#endif
//somewhere inside the code
NATIVEUNITID is #"unitid_release"
May be I do not understand something. But why? What is the proper way to define
NATIVEUNITID using the other define?
I've tried both #if (MYDEBUG) and #if (MYDEBUG == true) but I obtain the same result.
Please, help me to understand this simple case. How can I receive
NATIVEUNITID is #"unitid_debug" ?
The preprocessor cannot evaluate == for "strings".
You could retain your notation if you write #DEFINE YES 1
To improve this answer
#if !defined(YES)
#define YES (BOOL)1
#endif
#if !defined(NO)
#define NO (BOOL)0
#endif
before
#define MYDEBUG YES
Is there any way to get the device type as a #define? I want to get this for an Universal app and I want to be able to know if it is an iPad, iPhone4 or iPhone5.
Thanks!
#define IS_WIDESCREEN ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )
#define IS_IPHONE ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone )
#define IS_IPHONE_5 ( IS_IPHONE && IS_WIDESCREEN )
#define IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
Counter question:
Why use a macro, when there are methods available?
The macro translates into a method call any way, as you cannot know at compile time what device you’ll be confronted with at run time.
The device you’re running on is an iPad, if it says so:
BOOL isThisAnIPad = [[UIDevice currentDevice] userInterfaceIdiom] == UIInterfaceIdiomPad;
Apart from that, you automatically get the right resources by suffixing them with the correct values in combination with the usual #2x for retina graphics.
Code below yields the output "yes defined", "no defined" and "yes". Why?
#define FOOBAR NO
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#ifdef YES
NSLog(#"yes defined");
#endif
#ifdef NO
NSLog(#"no defined");
#endif
#if FOOBAR == YES
NSLog(#"yes");
#else
NSLog(#"no");
#endif
// ...
}
YES and NO are not undefined, objc.h defines them as:
typedef signed char BOOL;
#define YES (BOOL)1
#define NO (BOOL)0
What is the value of NO? If it's undefined (like YES), they will both evaluate to 0.
This means your expression is essentially
#if 0 == 0
which is of course true, and thus causes the first call to be compiled.
UPDATE: Not sure how BOOL is defined, but casting to what might be a typedef:ed type is not a very good idea when dealing with the preprocessor. Remember that the the #if is evaluated by the preprocessor, not by the compiler. Read something like this for more information about expressions in the preprocessor. Especially:
The preprocessor does not know anything about types in the language.
All identifieres that the preprocessor doesn't know of are replaced with 0 for evaluation in #if directives. If you don't have defined YES and NO both are 0 (and thus equal).
I have read many definitions of # if and # define statement.
I tried to use the way I read, but only with the error "Invalid token at start of a preprocessor expression" on the line that defines it as a comment below:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#define is_ipad (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define is_ipad_hd ( (is_ipad == 1 && [UIScreen mainScreen].bounds.size.width > 1024 ) ? YES : NO)
#define is_iphone_hd ([UIScreen mainScreen].bounds.size.width > 480 ? YES : NO)
#define device_width 480.0f
#define device_height 320.0f
#if (is_ipad_hd == YES) // Error here
#define device_width = 2048.0f
#define device_height = 1496.0f
#endif
Why it works in simple tutorials and when we try something more complex these things happen!
These are preprocessor directives, so you don't have access to [UIScreen mainScreen] methods and all other objects that are defined upon compilation!
Macro evaluation happens at compile time.
However, (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) or [UIScreen mainScreen] can only be interpreted at run time.
Beyond that, you should not be relying on the screen size to do your dirty work for you. You should instead be relying on the user interface idiom and the scale of the main screen:
BOOL isiPad = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad;
BOOL isHD = [[UIScreen mainScreen] scale] == 2.0;
if (isiPad) {
if (isHD) {
// retina iPad
} else {
// non-retina iPad
}
} else {
if (isHD) {
// retina iPhone/iPod touch
} else {
// non-retina iPhone/iPod touch
}
}
Agree with others here although I'm not as well versed in the C preprocessor a quick googling came back with this:
expression is a C expression of integer type, subject to stringent restrictions. It may contain....
much better formatting than I can quickly achieve here on the source.
Is it possible to use some thing like this in Objective-C:
#define number_of_items 10
and then using it as:
int arr[number_of_items];
Yes, assuming you mean Objective C. It's pretty much a superset of "proper" C so this is perfectly okay. It's also okay in both C and C++.
You can see that it works in the following transcript:
pax> cat qq.m
#import <objc/Object.h>
// First method.
#define number_of_items 10
int arr[number_of_items];
// Second method.
#define NUMBER_OF_ROWS 10
#interface test : Object{ int xyzzy[NUMBER_OF_ROWS]; }
#end;
pax> vi qq.m ; gcc -o qq.o -c qq.m -lobjc
pax> # no errors occurred
And, now that we've finally seen what you're actually using:
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define NUMBER_OF_ROWS_ (IS_IPAD? 18: 18)
NUMBER_OF_ROWS_ is not a constant, since it depends on the return value of the function UI_USER_INTERFACE_IDIOM().
In other words, it cannot be calculated at compile time. That's why you're getting the error. You can see this by compiling the following code:
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define NUMBER_OF_ROWS_ (IS_IPAD ? 18: 20)
int UI_USER_INTERFACE_IDIOM(void) {return 20;}
int UIUserInterfaceIdiomPad;
int main (void) {
int arr[NUMBER_OF_ROWS_];
return 0;
}
Under gcc --pedantic, you get:
qq.m: In function ‘main’:
qq.m:8: warning: ISO C90 forbids variable length array ‘arr’
You either need to use a dynamically adjustable collection like NSMutableArray or use an array of the maximum size desired and only use what you need of that.