What's the best way to define the following ternary operator?
[[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? x : y
I considered using the macro
#define phonePad(x, y) ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? x : y)
But this article mentions that it may not be the best idea. Is there a way to do the equivalent using a C function or is this the best way of implementing it?
I wouldn't use a macro for this. By using a macro, you require for the device to check the user interface idiom ever time this is used, and set x or y accordingly. Consider making a new method that returns based on the interface idiom. This can be static, because it's impossible for this value to ever change at runtime.
- (id)determineXOrY {
static id obj = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
obj = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? x : y
});
return obj;
}
Neither.
BOOL isiPhone = ([[UIDevice currentDevice] userInterfaceIdiom]
== UIUserInterfaceIdiomPhone);
foo = isiPhone ? x : y;
bar = isiPhone ? xprime : yprime;
...
If you turn that into a macro, you'll get a bunch of unnecessary calls into the Objective-C runtime. So just cache the result. Plus, it'll probably be a lot easier to read if you just write plain C code instead of using a macro.
If you do use the macro you must add some parentheses:
#define phonePad(x, y) ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone ? (x) : (y))
Without the parentheses you will have serious issues if x or y are more than simple values.
One downside to the macro is that you really need to be sure that both x and y evaluate to the same non-ambiguous data type.
Related
I need my app to support iOS 5+. Since prior iOS 6 the enum lineBreakMode for line break mode in UILabel is of type UILineBreakMode, and it is of type NSLineBreakMode for iOS 6+, what should be the best (or more correct) way to check the iOS version currently running to determine the type to be used? Is it correct to directly do something like [[UIDevice currentDevice] systemVersion], or is there a better way?
Thanks!
You do not need to check the iOS version at runtime, the enum values are the same, the compiled code will not be changed when moving from UILineBreakMode to NSLineBreakMode
enum {
NSLineBreakByWordWrapping = 0,
NSLineBreakByCharWrapping,
NSLineBreakByClipping,
NSLineBreakByTruncatingHead,
NSLineBreakByTruncatingTail,
NSLineBreakByTruncatingMiddle
};
typedef NSUInteger NSLineBreakMode
typedef enum {
UILineBreakModeWordWrap = 0,
UILineBreakModeCharacterWrap,
UILineBreakModeClip,
UILineBreakModeHeadTruncation,
UILineBreakModeTailTruncation,
UILineBreakModeMiddleTruncation,
} UILineBreakMode;
In case you want to check for the OS version you can use this code:
+ (NSInteger)OSVersion
{
static NSUInteger _deviceSystemMajorVersion = -1;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_deviceSystemMajorVersion = [[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:#"."][0] intValue];
});
return _deviceSystemMajorVersion;
}
This question already has answers here:
Check if a method exists
(5 answers)
Closed 9 years ago.
I have a piece of code that only works on iOS 6 or greater.
control.tintColor = [UIColor greenColor];
Is there a ready to use compiler directive like #ifdef iOS6_or_greater?
It's best if you check against the functionality, instead of the iOS version.
For example you can use respondsToSelector to see if a given method is supported.
[someObject respondsToSelector:#selector(someMethod)]
Failing that, there is a preprocessor directive
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000
- (BOOL)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
#endif
I just give you basic code of compare system version
Write following code in
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
your projectName-Prefix.pch so you can access it in anywhere you want .
And apply it as condition such like
if( SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6") )
{
}
else
{
}
you can go for this...........
float currSysVerFloat = [[[UIDevice currentDevice] systemVersion]floatValue];
if (currSysVerFloat>=6.0) {
isversion6=TRUE;
control.tintColor = [UIColor greenColor];
//This is iOS6 or greater
} else {
//do nothing
isversion6 = FALSE;
}
I have a Constants.h file in my app, where I #define app-wide things for easy access later. I'm having a hard time, though, #defineing based on iOS version. Here's what I've tried:
#ifdef __IPHONE_7_0
#define kHamburgerImage [UIImage imageNamed:#"reveal_menu_icon_portrait_ios7.png"];
#else
#define kHamburgerImage [UIImage imageNamed:#"reveal_menu_icon_portrait.png"];
#endif
Just because it says iOS 7 in there doesn't mean this is under NDA, O closers!
Which works fine - for iOS 7. When I run my app on iOS 6, however, the #define is still the iOS 7 one - it seems as though the #ifdef is never taken into account.
What can I do to fix this?
Instead of using compile-time checks, you need runtime checks. This means you can't use #define. I suggest using a static variable that is initialized at runtime based on the version of iOS. Below is an example if you only need the value in a single file.
Some .m file:
static UIImage *kHamburgerImage = nil;
+ (void)initialize {
// This assumes you only support iOS 6 and later - adjust as needed
if ([[UIDevice currentDevice].systemVersion hasPrefix:#"6"]) {
kHamburgerImage = [UIImage imageNamed:#"reveal_menu_icon_portrait.png"];
} else {
kHamburgerImage = [UIImage imageNamed:#"reveal_menu_icon_portrait_ios7.png"];
}
}
Edit: Since these need to be globals, you should do this:
Constants.h:
extern UIImage *kHamburgerImage;
#interface Constants
#end
Constants.m:
UIImage *kHamburgerImage = nil;
#implementation Constants
+ (void)initialize {
// This assumes you only support iOS 6 and later - adjust as needed
if ([[UIDevice currentDevice].systemVersion hasPrefix:#"6"]) {
kHamburgerImage = [UIImage imageNamed:#"reveal_menu_icon_portrait.png"];
} else {
kHamburgerImage = [UIImage imageNamed:#"reveal_menu_icon_portrait_ios7.png"];
}
}
#end
But this suffers from a problem. Unless you take specific steps, accessing these globals could result in nil pointers. They only get initialized if the class is actually referenced. I suggest that as the first line of your application:didFinishLaunchingWithOptions: you do:
[Constants class];
This ensures the initializer is called and the constants are setup before you use them anywhere else in your code.
You can at least shorten your code by defining the iOS check as a macro.
#define IS_IOS7 [[UIDevice currentDevice].systemVersion hasPrefix:#"7"]
And then your new code is way more readable,
if (IS_IOS7) {
kHamburgerImage = [UIImage imageNamed:#"reveal_menu_icon_portrait_ios7.png"];
} else {
kHamburgerImage = [UIImage imageNamed:#"reveal_menu_icon_portrait.png"];
}
You should use #ifndef instead of #ifdef. Here is the code . I hope it will help you.
#ifndef __IPHONE_7_0
#define kHamburgerImage [UIImage imageNamed:#"reveal_menu_icon_portrait_ios7.png"];
#else
#define kHamburgerImage [UIImage imageNamed:#"reveal_menu_icon_portrait.png"];
#endif
I'm getting an error when I create a new project skeleton using phonegap 2.4 in my CDVLocation.m file. The error I'm getting is
if ([cdvViewController supportsOrientation:currentOrientation]) Implicit conversion from enumeration type "UIDeviceOrientation"(aka "enum UIDeviceOrientation") to different enumeration type "UIInterfaceOrientation" (aka "enum UIInterfaceOrientation")
Im not 100% sure whats going on here since I dont know OBJ-C, any idea?
currentOrientation is of type UIDeviceOrientation which has more values thanUIInterfaceOrientation
Since the method expects a UIInterfaceOrientation instead of a UIDeviceOrientation
Replace:
supportsOrientation:currentOrientation
with
supportsOrientation:[[UIApplication sharedApplication] statusBarOrientation]]
Try changing the method in CDVLocation.m:
if ([self.locationManager respondsToSelector:#selector(headingOrientation)]) {
UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
if (currentOrientation != UIDeviceOrientationUnknown) {
CDVViewController* cdvViewController = (CDVViewController*)self.viewController;
//change this line
if ([cdvViewController supportsOrientation:[[UIApplication sharedApplication] statusBarOrientation]]) {
self.locationManager.headingOrientation = (CLDeviceOrientation)currentOrientation;
// FYI UIDeviceOrientation and CLDeviceOrientation enums are currently the same
}
}
}
I am sure that this probably something extremely easy (or it can't be done), but I can't seem to find anything on it.
In one of my classes .h file I need to determine if the app is running on an iPad or an iPhone. Then change the value of the #define accordingly.
Ideally I would this it would look something like this:
#if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone
#define deltaX 10.0
#define theda 15.0
#define threshHold 267.0
#endif
#if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad
#define deltaX 78.1
#define theda 67.2
#define threshHold 453.0
#endif
I am not sure what to use, any help would be very much appreciated.
Thank you for your time!
A little late to the party, but figured I'd share what worked for me.
A solution that has been working for me is to define IS_IPAD and IS_IPHONE somewhere like so
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define IS_IPHONE (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
Then when needing the other defines based on ipad/iphone, do something like this
#define deltaX (IS_IPAD? 78: 10)
Sadly, you can't do this, as in a universal app the same code runs on iPhone as on iPad, so this decision must be made at run-time, not compile-time.
You should declare these variables in a header file, and then set them at run time depending on the value of UI_USER_INTERFACE_IDIOM().
You already have the code to determine the device, so that's fine.
I'd create your defines as follows:
#define padDeltaX 10.0
#define phoneDeltaX 78.1
... etc
Then in your class file:
if (if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
// do iPhone processing with the variables
}
else
{
// must be iPad
}
Alternatively:
float variableOne, variableTwo; // etc
if (if UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
variableOne = phoneDeltaX;
variableTwo = phoneTheta; // etc
}
else
{
// must be iPad
variableOne = padDeltaX;
variableTwo = padTheta; // etc
}
// now do the shared processing with variableOne, variableTwo etc
Hope this helps!