In my MotionManager wrapper class I have this one code snippet that repeats for each of it's function. This code is there to make the app runable on simulator without otherwise required gyroscope in device. The code snippet I'm using looks like this:
#if !TARGET_IPHONE_SIMULATOR && TARGET_OS_IPHONE
return // Do nothing if in simulator
#endif
I would like to replace this code with a single line of code stating clearly what it does and isn't so ugly. If I was writing this in C++ I would simply use macro that would look something like this:
#define skipIfSimulator #if !TARGET_IPHONE_SIMULATOR && TARGET_OS_IPHONE /
return /
#endif
So instead of this:
func foo() {
#if !TARGET_IPHONE_SIMULATOR && TARGET_OS_IPHONE
return // Do nothing if in simulator
#endif
...
}
There would be this:
func foo() {
skipIfSimulator
...
}
What is the best way to achieve this while adding preferably no overhead?
I've come up with a pretty poor work-around. But it can satisfy your need.
#if !TARGET_IPHONE_SIMULATOR && TARGET_OS_IPHONE
BOOL const kIsSimulator = NO;
#else
BOOL const kIsSimulator = YES;
#endif
#define SIM(x) if (kIsSimulator) {x; return;}
Usage:
SIM(`any_statement`);
Example usage:
SIM(NSLog(#"on Simulator"));
or,
SIM(); // No statement at all
Self contained example: Objective-C
#import "ViewController.h"
#if !TARGET_IPHONE_SIMULATOR && TARGET_OS_IPHONE
BOOL const kIsSimulator = NO;
#else
BOOL const kIsSimulator = YES;
#endif
#define SIM(x) if (kIsSimulator) {x; return;}
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[self printAMessage];
}
- (void)printAMessage {
SIM(NSLog(#"on Simulator"));
NSLog(#"on iPhone");
}
#end
Unfortunately can't reproduce same with Swift.
Related
I am using PKRevealController to create SplitView in my app. In PKRevealController.m file i am giving the value to how much screen will reveal using this code
#define DEFAULT_LEFT_VIEW_WIDTH_RANGE NSMakeRange(273, 310)
This is for iPhone but now i want to make loop to select the size. if device is iPad than large else small so how can i do this because its outside of #interface PKRevealController
I have check some code on google and i find like this
#if defined(__IPHONE_6_0) || defined(__MAC_10_8)
#define AF_CAST_TO_BLOCK id
#else
#define AF_CAST_TO_BLOCK __bridge void *
So can i create something like this for selecting device?
You can use this code to achive this change value according to your need
In your PKRevealController.m
#define DEFAULT_LEFT_VIEW_WIDTH_RANGE_iPad NSMakeRange(700, 700)
#define DEFAULT_LEFT_VIEW_WIDTH_RANGE_iPhone NSMakeRange(273, 310)
#define DEFAULT_RIGHT_VIEW_WIDTH_RANGE_iPad DEFAULT_LEFT_VIEW_WIDTH_RANGE_iPad
#define DEFAULT_RIGHT_VIEW_WIDTH_RANGE_iPhone DEFAULT_LEFT_VIEW_WIDTH_RANGE_iPhone
And in iterface find out setup method an replace it with this method
pragma mark - Setup
- (void)setup
{
self.state = PKRevealControllerFocusesFrontViewController;
if ([[UIDevice currentDevice] userInterfaceIdiom] ==UIUserInterfaceIdiomPhone)
{
//device is iPhone
self.leftViewWidthRange = DEFAULT_LEFT_VIEW_WIDTH_RANGE_iPhone;
self.rightViewWidthRange = DEFAULT_RIGHT_VIEW_WIDTH_RANGE_iPhone;
}
else
{
//device is iPad
self.leftViewWidthRange = DEFAULT_LEFT_VIEW_WIDTH_RANGE_iPad;
self.rightViewWidthRange = DEFAULT_RIGHT_VIEW_WIDTH_RANGE_iPad;
}
self.view.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
}
Than it should be work..:)
I don't really think there is a way to do that, usually problem like that is solved by making 2 #define statements, like this:
#define DEFAULT_LEFT_VIEW_WIDTH_RANGE_IPHONE NSMakeRange(273, 310)
#define DEFAULT_LEFT_VIEW_WIDTH_RANGE_IPAD NSMakeRange(273, 310)
and then when you have to use it in code just check the device type like this:
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
/* code that uses DEFAULT_LEFT_VIEW_WIDTH_RANGE_IPAD */
}
else {
/* code that uses DEFAULT_LEFT_VIEW_WIDTH_RANGE_IPHONE */
}
I have a Constants.h file which contains some global constants in fact. Since my application is built both for iPhone and iPad, i would like to define the same constants (ie with the same name) differently for the two device types.
For a complete explanation:
/******** pseudo code *********/
if (deviceIsIPad){
#define kPageMargin 20
}
else {
#define kPageMargin 10
}
How can I do this?
Thanks.
L.
It's impossible to get device type during preprocessing step. It is determined dynamically during runtime. You have two options:
Create two different targets (for iPhone and iPad respectively) and define macro there.
Create macro that inserts expression like this:
#define IS_IPAD (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad)
#define kMyConstant1 (IS_IPAD ? 100 : 200)
#define kMyConstant2 (IS_IPAD ? 210 : 230)
#define kMyConstant3 (IS_IPAD ? #"ADASD" : #"XCBX")
#define are resolved at compile time, ie on your computer
Obviously, you can't make them conditional the way you want. I recommend creating static variable and setting them on the +(void)initialise method of your class.
And for the condition, use something like
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// iPad
} else {
// iPhone or iPod touch.
}
So that would go
static NSInteger foo;
#implementation bar
+(void)initialise{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// iPad
foo = 42;
} else {
// iPhone or iPod touch.
foo = 1337;
}
}
#end
Use UIDevice Macros - http://d3signerd.com/tag/uidevice/
Then you can write code like;
if ([DEVICE_TYPE isEqualToString:DEVICE_IPAD]) {
}
or
if (IS_SIMULATOR && IS_RETINA) {
}
You can't do this with defines, as they're expanded at compilation time. However, you can define variables and set their initial value based on the user interface idiom:
// SomeClass.h
extern CGFloat deviceDependentSize;
// SomeClass.m
- (id)init
{
// ...
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad])
deviceDependentSize = 1024.0f; // iPad
else
deviceDependentSize = 480.0f; // iPhone
// etc.
}
Hi write this code in appdelegate class
+(NSString *)isAppRunningOnIpad:(NSString *)strNib{
NSString *strTemp;
NSString *deviceType = [UIDevice currentDevice].model;
if ([deviceType hasPrefix:#"iPad"]){
strTemp=[NSString stringWithFormat:#"%#I",strNib];
}
else{
strTemp=strNib;
}
return strTemp;
}
call this from your class using this line
SecondVC *obj_secondvc = [[SecondVC alloc] initWithNibName:[AppDelegate isAppRunningOnIpad:#"SecondVC"] bundle:nil];
I am using conditional code as below,
I want to run certain code only in ios5.0 and > ios5.0( i mean i want to support ios5.0 and 5.1 version too)
But the below condition dos not seem to work. ( Currently my development version is 5.1 but the below snippet is not getting identified.the control is not going into it.)
Please let me know your thoughts
#ifdef __IPHONE_5_0_OR_LATER
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_5_0
// iPhone 5.0 code here
#endif
#define __IPHONE_2_0 20000
#define __IPHONE_2_1 20100
#define __IPHONE_2_2 20200
#define __IPHONE_3_0 30000
#define __IPHONE_3_1 30100
#define __IPHONE_3_2 30200
#define __IPHONE_4_0 40000
#define __IPHONE_4_1 40100
#define __IPHONE_4_2 40200
#define __IPHONE_4_3 40300
#define __IPHONE_5_0 50000
#define __IPHONE_5_1 50100
#define __IPHONE_NA 99999 /* not available */
How to target a specific iPhone version?
#ifdef is a compile directive, thus it will be evaluated at compile time not run time.
Thus if you add this to you code, the methods call in the if will all ways be called if your target SDK matches your #ifdef. So if you compile an app for both iOS 4 and 5 and place all the 5 only methods in #ifdef io5 the app will crash on iOS 4 since the methods will be called.
If you want to check if some method is available then you should do like :
Here is an example for dismissing an modal view controller from it's parent. Since parentViewController is changed to presentingViewController in iOS 5, we check if presentingViewController is available and use it.
if ([self respondsToSelector:#selector(presentingViewController)]) {
[self.presentingViewController dismissModalViewControllerAnimated:YES];
} else {
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
The same with goes for checking if a class is available :
if ([MPNowPlayingInfoCenter class]) {
MPNowPlayingInfoCenter *center = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *songInfo = /* ... snip ... */;
center.nowPlayingInfo = songInfo;
}
NSArray *versionCompatibility = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
if ( 5 == [[versionCompatibility objectAtIndex:0] intValue] ) { /// iOS5 is installed
// Put iOS-5 code here
} else { /// iOS4 is installed
// Put iOS-4 code here
}
#ifdef doesn't work. But why?
CGFloat maxScale;
if ( [[UIScreen mainScreen] respondsToSelector: #selector (scale)] == YES )
{
NSLog (#"case1");
#define GLOBAL1
}
else
{
NSLog (#"case2");
#undef GLOBAL1
}
#ifdef GLOBAL1
NSLog (#"first");
maxScale = 1.0 / [[UIScreen mainScreen] scale];
#else
NSLog (#"second");
maxScale = 1.0;
#endif
#undef GLOBAL1
my log:case1, second. But it must be case1, first.
#define, #ifdef are pre-processor macros/conditionals. That means that the logic contained in them is compiled before your code is compiled. It is not actually part of your code.
See this guide for learning what pre-processor macros/conditionals are and do.
[EDIT]
This is what your pre-processor sees when it reads your code.
#define GLOBAL1
#undef GLOBAL1
#ifdef GLOBAL1
//...
#else
//...
#endif
#undef GLOBAL1
it IGNORES all other code and logic.
This is the actual code output the compiler makes:
if ( [[UIScreen mainScreen] respondsToSelector: #selector (scale)] == YES )
{
NSLog (#"case1");
}
else
{
NSLog (#"case2");
}
// because the pre-processor #undef GLOBAL1
NSLog (#"second");
maxScale = 1.0;
The pre-processor code is "executed" telling the compiler how to compile, and will not be used or run during run-time.
Hope that helps!
The preprocessor does not care that the #define is inside a coded if statement - it is processed before the code and only cares about other preprocessor definitions. You can't use #defines and other preprocessor commands (such as #undef) as code- they will not be hit each time the code enters the conditional branches.
Using the TARGET_IPHONE_SIMULATOR macro results in the same constant values being defined in am application. For example:
#ifdef TARGET_IPHONE_SIMULATOR
NSString * const Mode = #"Simulator";
#else
NSString * const Mode = #"Device";
#endif
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
...
NSLog(#"Mode: %#", Mode);
...
}
Always results in "Mode: Simulator" being logged. I'm currently running XCode 3.2.4 if that helps. Thanks.
TARGET_OS_SIMULATOR is defined on the device (but defined to false). The fix is:
#include <TargetConditionals.h> // required in Xcode 8+
#if TARGET_OS_SIMULATOR
NSString * const Mode = #"Simulator";
#else
NSString * const Mode = #"Device";
#endif
Not sure when this was changed. I'm fairly sure it was possible to use 'ifdef' in the past.
For me explicitly including TargetConditionals.h helped
#include <TargetConditionals.h>
Try TARGET_OS_SIMULATOR, as TARGET_IPHONE_SIMULATOR is deprecated.
I would try implement macro if its going to be used on different classes through out the app.
in pch file ,
#if TARGET_IPHONE_SIMULATOR
#define isSimulator() YES
#else
#define isSimulator() NO
#endif
and in any class I can check by calling isSimulator().
For some reason TARGET_IPHONE_SIMULATOR doesn't work for me in xcode v6.4 . The snippet below works perfectly :
#if (!arch(i386) && !arch(x86_64))
camera = Camera()
#else
camera = MockCamera()
#endif
Swift:
#if targetEnvironment(simulator)
showSimulatorOnlyError()
#endif