Objective-C has an @available expression in XCode 9+ / LLVM 5+ that allows you to guard a block of code to at least a certain OS version so that it won\'t emit unguarded ava
Defined
#define AT_AVAILABLE(...) \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wunsupported-availability-guard\"") \
_Pragma("clang diagnostic ignored \"-Wunguarded-availability-new\"") \
__builtin_available(__VA_ARGS__) \
_Pragma("clang diagnostic pop")
Usage:
if (AT_AVAILABLE(iOS 11.0, *) && some_condition) {
// code to run when on iOS 11+ and some_condition is true
}else {
// code to run when on older iOS or some_condition is false
}
import this in PCH file
#pragma clang diagnostic ignored "-Wunsupported-availability-guard"
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
Usage:
if (AT_AVAILABLE(iOS 11.0, *) && some_condition) {
// code to run when on iOS 11+ and some_condition is true
}else {
// code to run when on older iOS or some_condition is false
}
How about wrapping the AND up in a function?
typedef BOOL (^Predicate)();
BOOL elevenAvailableAnd(Predicate predicate)
{
if (@available(iOS 11.0, *)) {
return predicate();
}
return NO;
}
Then you only have one branch:
if (elevenAvailableAnd(^{ return someCondition })) {
// code to run when on iOS 11+ and some_condition is true
}
else {
// code to run when on older iOS or some_condition is false
}
Or you could do without the Block if you prefer:
BOOL elevenAvailableAnd(BOOL condition)
{
if (@available(iOS 11.0, *)) {
return condition;
}
return NO;
}
inline bool iOS13()
{
if(@available(iOS 13, *))
return true;
else
return false;
}
if(iOS13() && x == y)
//...
You could also simply use a flag:
BOOL doit = FALSE;
if (@available(iOS 11.0, *)) {
if (some_condition) {
doit = TRUE;
}
}
if (doit) {
// code to run when on iOS 11+ and some_condition is true
} else {
// code to run when on older iOS or some_condition is false
}
The way I came up with that seems to change the layout of the code the least is:
do {
if (@available(iOS 11.0, *)) {
if (some_condition) {
// code to run when on iOS 11+ and some_condition is true
break;
}
}
// code to run when on older iOS or some_condition is false
} while (0);
which is still ugly.
You do what you always do when you have complex conditional code in the middle of a function that makes the flow complex: you hoist it into another function.
- (void)handleThing {
if (@available(iOS 11.0, *)) {
if (some_condition) {
// code to run when on iOS 11+ and some_condition is true
return;
}
}
// code to run when on older iOS or some_condition is false
}
Or you hoist the check into generic code (see Josh Caswell's; it's better than how I originally wrote this).