How to set an enum not present in current iOS version? - ios

I am trying to set linebreakmode for textLabel in UIButton.
self.scheduleButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
NSLineBreakByWordWrapping won't be available prior to iOS 6.0.
self.scheduleButton.titleLabel.lineBreakMode = UILineBreakModeWordWrap;
will work prior to iOS6 but XCode is throwing an error saying, it doesn't recognize UILineBreakModeWordWrap.
How do I make sure that UILineBreakModeWordWrap code is completely ignored prior to iOS 6.
I have made a macro to check OS version, I would have used respondsToSelector, had it been a case with a method but this is an enum type.
SYSTEM_VERSION_LESS_THAN(#"6.0")
I am using this here but in an if-else scenario but it wont still work as XCode will still tell me that UILineBreakModeWordWrap is not recognizable.
Is there a way I can know OS version at pre-processing level ?
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
This macro that I have made will just add Objective C code to determine OS type which means the check will happen at runtime.
but because of this XCode will not ignore UILineBreakModeWordWrap.

Both NSLineBreakByWordWrapping and UILineBreakModeWordWrap have the same value. As long as your Base SDK is 6.0 or later then using NSLineBreakByWordWrapping will make the compiler happy and it will work for any version of iOS at runtime.

Option:1
You cane create your own macros to handle this:
#ifdef __IPHONE_6_0
# define LINE_BREAK_MODE_WORD_WRAP NSLineBreakByWordWrapping
#else
# define LINE_BREAK_MODE_WORD_WRAP UILineBreakModeWordWrap
#endif
Now in code you can use, LINE_BREAK_MODE_WORD_WRAP
Option:2
Directly use enum value instead of reference name, both NSLineBreakByWordWrapping and UILineBreakModeWordWrap are having same value - 0
Hence you can directly write this way as well -
self.scheduleButton.titleLabel.lineBreakMode = 0;
It will automatically picks up 0th value from iOS SDK enumeration reference.
Hope this helps.

Related

How to continue to support iOS 5.1 as functions became deprecated

I have an app that must work for iOS versions >= 5.1.
Apple docs say that "The AudioSession API has been completely deprecated in iOS 7.0". And one should use AVAudioSession class instead.
But the method that I need (- (BOOL)setCategory:(NSString *)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError) is only available starting from iOS 6.0.
So it seems that I have to continue usage of deprecated AudioSessionSetProperty to support iOS 5.1.
What is a correct way to handle such situations (my question is general, not only about this particular problem with audio)? Should I write something like
if ([[[UIDevice currentDevice] systemVersion] compare:#"6.0" options:NSNumericSearch] == NSOrderedAscending)
{
// use deprecated methods (AudioSessionSetProperty)
}
else
{
// use brand-new methods (AVAudioSession)
}
or maybe it's ok to just use AudioSessionSetProperty until it stops to compile?
Deprecated methods doesn't stops you from using it, but yes if its deprecated from your current selected iOS version then it'll give you warning. An example, if your app still supporting iOS < 6.0 and you're need to change alignment of UILabel then you can do it like this,
if ([[[UIDevice currentDevice] systemVersion] compare:#"6.0" options:NSNumericSearch] == NSOrderedDescending)
{
lbl.textAlignment = UITextAlignmentCenter;
//for iOS < 6.0, warning when deployment target is iOS 5.0
}
else
{
lbl.textAlignment = NSTextAlignmentCenter; //for iOS >= 6.0
}
OR
lbl.textAlignment = UITextAlignmentCenter; //with warning in iOS 6.0
OR
lbl.textAlignment = NSTextAlignmentCenter; //will crash in iOS 5.0
PS. better to support iOS 7.0 and higher (not even iOS 6.0 as Apple wouldn't allow apps with iOS6.0 from coming Feb as commented by #ahwulf.), as latest iOS 8 was released with lots of good features and most of the people updated their phone with this. This will help you in two cases, you'll not need to check for iOS version compatibility and your code looks nice without warnings :) but still its all depends your needs.
Update:
OR
as #rmaddy suggested one should check for existence of method using respondsToSelector:
UILabel *label;
if([label respondsToSelector:#selector(textAlignment)]) {
label.textAlignment = NSTextAlignmentCenter;
}
In above example, we're checking (but in real we're already know this) whether UILabel has textAlignment property or not.

How to use preprocessors in objective c

Hi in one of my applications I have to support that app for IOS6 & IOS7.Inorder to accomplish that first I have to know the current device version. For that I had defined one macro and I am trying to using that macro as a reference to accomplish my task. The code which I wrote is as such below.
In .h file I defined IPhoneOSVersion as 50000.
This code is in .m file
if([[[UIDevice currentDevice] systemVersion] isEqualToString:#"7.0"])
{
#undef IPhoneOSVersion
#define IPhoneOSVersion 70000
NSLog(#"_IPHONE_OS_VERSION_MIN_REQUIRED after is %d",IPhoneOSVersion);
}
else
{
#undef IPhoneOSVersion
#define IPhoneOSVersion 60000
NSLog(#"_IPHONE_OS_VERSION_MIN_REQUIRED after is %d",IPhoneOSVersion);
}
NSLog(#"_IPHONE_OS_VERSION_MIN_REQUIRED after is %d",IPhoneOSVersion);
And if i run this code in IOS7. In console the data have to print like this _IPHONE_OS_VERSION_MIN_REQUIRED after is 70000 but unfortunately I am getting _IPHONE_OS_VERSION_MIN_REQUIRED after is 60000. Even I put a break points at else condition also but that is not executing but the macro value is changing.Can anyone please let me know why the macro value changing like this.
You shouldn't be hardcoding against the OS version, Apple recommended way of supporting multiple OS versions is to check for some specific class, API, protocol or function, this allows for greater flexibility as some of that stuff is sometimes backwards compatible.
Here's a pretty decent tutorial on how to check for existence of specific resources in code http://www.raywenderlich.com/42591/supporting-multiple-ios-versions-and-devices and the docs from Apple https://developer.apple.com/library/ios/documentation/developertools/conceptual/cross_development/Using/using.html
EDIT: To answer your question on why the macro is changed, the compiler goes over both branches of the if-else, thus the last declaration of the macro is used. You can't use a macro like that and change it during runtime, macros are meant to be define before compilation.
You use the preprocessor in Objective-C in exactly the same way as in C or C++. The preprocessor doesn't care about your if/else statements. It sees a sequence of #undef, #define, #undef, #define and performs them one after the other, so in your last line, the last #define is in effect. You cannot influence these #defines with anything happening at runtime.
There are always three OS versions in play: The deployment target (that is the lowest OS version where you allow your app to run), the SDK version, and the actual version at runtime. The first two you set in Xcode; the actual version is obviously out of your control except that you know it is the same or higher than the deployment target.
__IPHONE_OS_VERSION_MIN_REQUIRED = Deployment target
__IPHONE_OS_VERSION_MAX_ALLOWED = SDK version
Try with
if([[[UIDevice currentDevice] systemVersion] floatValue] == 7.0)

Support of several iOS - application development

With the release of iOS6, I am going to update my application using the new feature of iOS6, such as UICollectionView.
When I will deploy it on App Store, my application will be only available for devices on iOS6.
Question: How can I let the devices on iOS 5.1 using the older release which do not use UICollectionView?
I could go more deeper by asking: What is the strategy to upgrade an application without loosing the users which have not yet upgrade their OS?
Thank you for your advice.
You could check for availability of new iOS6 classes with Class tmp = NSClassFromString(#"UIActivityViewController");
if (tmp) {//use iOS6 class}else{//do something else}. Also, you could use some macros, like __IPHONE_5_0, put some code between #ifndef or #if defined(...). Good Luck!
This one will work perfectly:
NSString * systemVersion = [[UIDevice currentDevice] systemVersion];
if ([self.systemVersion compare:#"5.0" options:NSNumericSearch] != NSOrderedAscending)
{
osHigherThaniOS5 = TRUE;
}
if ([self.systemVersion compare:#"6.0" options:NSNumericSearch] != NSOrderedAscending)
{
osHigherThaniOS6 = TRUE;
}
Just determine the system version and set your conditions accordingly :)

Literal #YES not working in iOS 5 / Xcode 4.4

New Xcode 4.4 is out and it should support literals like
#42
#"String"
#23.0L
#{ #"key" : obj } and
#[obj1, obj2]
and it should also support #YES and #NO, which isn't working when targeting latest iOS 5 (and prior).
After compiling it show the error message:
Unexpected type name 'BOOL': expected expression
I know you can fix it by typing #(YES) and #(NO). But I want to know the reason why it isn't working as expected.
The reason is Apple forgot the parentheses here:
#define YES (BOOL)1
This will be fixed in iOS 6 SDK:
#define YES ((BOOL)1)
In the meantime you must type #(YES).
This is useful for information about literals.
A commenter on this answer also points out:
There is one small thing I'd like to warn about. Literal bools are also not supported
because of this. However, a quick fix that I implemented was adding
this to the beginning of one of my common headers (in an iOS project)
#ifndef __IPHONE_6_0
#if __has_feature(objc_bool)
#undef YES
#undef NO
#define YES __objc_yes
#define NO __objc_no
#endif
#endif
#phix23s answer seems to be more to the point. You should accept that.
This was worth adding from comments:
It should be noted that this needs to be done after the #import . If one puts these #defines in their Prefix.pch, they should make sure to import Foundation earlier in the pch

Is there a specific Xcode compiler flag that gets set when compiling for iPad?

Is there a specific Xcode compiler flag that gets set when compiling for iPad?
I want to conditionally compile iPad vs iPhone/iPod Touch code for example:
#ifdef TARGET_IPAD
code for iPad
#else
code for iPhone
#endif
I know there is already TARGET_OS_IPHONE and TARGET_CPU_ARM in TargetConditionals.h but anything that easily and specifically targets iPad?
-Rei
The correct API to use for run-time checking of iPad vs. iPhone/iPad Touch is:
BOOL deviceIsPad = ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad);
The UIDevice header filer also includes a convenient macro, UI_USER_INTERFACE_IDIOM(), which will be helpful if your deployment target is < iPhone 3.2.
#define UI_USER_INTERFACE_IDIOM() ([[UIDevice currentDevice] respondsToSelector:#selector(userInterfaceIdiom)] ? [[UIDevice currentDevice] userInterfaceIdiom] : UIUserInterfaceIdiomPhone)
So you could just say, negatively:
BOOL deviceIsPad = (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPhone);
Instead of using compile-time flags, you should use run-time check e.g. use NSClassFromString to see if a class exists because the same app can be installed on both devices.
And because of the possibility of running the app in both devices, there isn't a built-in compile-time check whether it targets iPad or not.
Currently I didn’t find anything that would let you check if you are on an iPad, but I’m also not sure if Apple recommends runtime checks. Here’s an excerpt from Apple:
In addition to your view controllers, any classes that are shared between iPhone and iPad devices need to include conditional compilation macros to isolate device-specific code. Although you could also use runtime checks to determine if specific classes or methods were available, doing so would only increase the size of your executable by adding code paths that would not be followed on one device or the other. Letting the compiler remove this code helps keep your code cleaner.
However, there is no place I could find more specific information about conditional compilation macros.
For multiple targets sharing the same project/code, I'm doing this by editing the C flags for my iPad target.
With the [myapp]-iPad target chosen as the active target, pick Project -> Edit Active Target [myapp]-iPad. Search for "c flags" and double-click. Add a flag for "-D TARGET_IPAD". Now the symbol TARGET_IPAD will be defined only for your iPad target.
Of course, this only works if you're using separate targets for iPad and iPhone. If you're running the same binary on both, obviously there's nothing the compiler can do for you. (However, the 3.2 SDK as of the end of January doesn't even support Universal apps yet.)
(Edited; I was confused about the terminology of "Universal" apps etc.)
Or -> just to be sure
-(BOOL)isDeviceAniPad
{
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 30200
BOOL deviceIsPad = ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad);
return deviceIsPad;
#endif
return NO;
}
I think this will do
-(BOOL)isDeviceAniPad
{
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 30200
return ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad);
#endif
return NO;
}

Resources