When a method can only be used on certain iOS versions, I usually check for its availability using respondsToSelector:.
With a const CGFloat declaration this is not possible.
The specific constant I'm trying to use is UIFontWeightBlack which is defined as:
UIKIT_EXTERN const CGFloat UIFontWeightBlack NS_AVAILABLE_IOS(8_2);
What is the best way to check if the iOS version my code is running in supports this constant?
Also if I want to support building my framework with older versions of the iOS SDK, what is the best way to check at compile time, if the used SDK offers this symbol?
I would currently do the check with
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_2
Is there a way to check for the symbol directly, without having to rely on / explicitly specify the iOS SDK version?
This is covered in the SDK Compatibility Guide.
Check the availability of an external (extern) constant or a notification name by explicitly comparing its address—and not the symbol’s bare name—to NULL or nil.
So your code would be:
if (&UIFontWeightBlack != NULL) {
// It is safe to use the constant
}
To answer the second part of your question, change your compile time check to the following:
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80200 // 80200 is the value of __IPHONE_8_2
We want to fall back to use the value of the macro rather than the macro itself as the macro is not defined in older versions of the iOS SDK.
As you mentioned in a comment, this is covered in the Conditionally Compiling for Different SDKs section:
The following code excerpt demonstrates this. Notice the use of the
numerical value 1050 instead of the symbol __MAC_10_5 in the #if
comparison clause: If the code is loaded on an older system that does
not include the symbol definition, the comparison still works.
Related
In typical Apple fashion, there's no documentation (and what little there borders on trolling). For example, what is simd_precise_normalize(_:)? You’d be forgiven for thinking it was a slower, more precise normalization than simd_fast_normalize(_:). But then why does simd_normalize(_:) exist?
Why is there simd_cross(simd_float3, simd_float3) and cross(SIMD3<Float>, SIMD3<Float>) when typealias simd_float3 = SIMD3<Float>?
And what about the Swift operator overloads on simd_float3?
I've written a bug to Apple about it, but does anyone know?
But then why does simd_normalize(_:) exist?
This comment explains it. simd_normalize is equivalent to simd_precise_normalize unless you are compiling with -ffast-math specified, in which case it is equivalent to simd_fast_normalize. I never used swift only objective-c, but it’s possible there’s equivalent option somewhere in compiler switches or xcode project settings.
Why is there simd_cross(simd_float3, simd_float3) and cross(SIMD3, SIMD3)
I think they are equivalent. Note that comments in the header discuss both C-style API like simd_cross(x,y) and C++ API simd::cross(x,y). It could be that in Swift both are available for some of these functions.
There is something about using g_autoptr() together with G_DEFINE_AUTOPTR_CLEANUP_FUNC() when using different GLib versions which I don't understand (this affects also the other g_auto... variants and its G_DEFINEs).
The documentation says
"The way to clean up the type must have been defined using the macro
G_DEFINE_AUTOPTR_CLEANUP_FUNC()"
When using for example GLib 2.62 and using the G_DEFINE macro this results in errors like
/usr/include/glib-2.0/glib/gmacros.h:1032:49: error: redefinition of ‘glib_slistautoptr_cleanup_GtkTreePath’
1032 | #define _GLIB_AUTOPTR_SLIST_FUNC_NAME(TypeName) glib_slistautoptr_cleanup_##TypeName
Leaving out the G_DEFINE macro will solve the problem and the program works just fine.
However, on older GLib versions like 2.50 (which is for example still used by Debian 9), using the G_DEFINE macro will not result in an error message. But I can't see any changes reflected by the GLib documentation. I cannot determine when exactly the aforementioned change of behaviour has been introduced. How am I supposed to cope with this when I want to support all GLib versions from 2.50 on?
The issue is probably in Gtk, not GLib. g_autoptr() was supported for most things in Gtk+ 3.22 (the one in Debian 9) already: so you shouldn't have to call G_DEFINE_AUTOPTR_CLEANUP_FUNC() on Gtk types yourself. GtkTreePath however was still missing a call: this was added in 3.24, see https://gitlab.gnome.org/GNOME/gtk/-/commit/86dd1e37a70e9bae057a9a11332f7254cda242e8.
You'll probably have to do the macro call behind a version check if you want to use g_autoptr() with TreePath on Gtk < 3.24.
Except for constants RTLVersion and CompilerVersion is there any way how to get version symbol like VER320 instead of following code?
'VER' + IntToStr(Trunc(CompilerVersion * 10))
The simple answer to the question is no. There is no mechanism for code to enumerate conditional symbols.
Your current approach is probably the best you can do, subject to there being no guarantee that future release of the compiler will follow the current VERxxx convention.
Of course, you may as well simply report the compiler version directly.
I'm compiling my first project with 64 bit support enabled. I'm running into a bunch of compiler warnings about implicit conversions to float. This is happening because I'm using fabsf() and assigning the result to a CGFloat (which is a double, not float on the new 64 bit architecture).
According to the answer on this question:
CGFloat-based math functions?
I just need to #include <tgmath.h> to solve this problem and probably change fabsf to fabs. I have at least one file where this doesn't seem to be helping. I still get the warning: implicit conversion loses floating-point precision 'double' to 'CGFloat' aka (float). Here's the line that generates that warning:
CGFloat deltaX = fabs(item.center.x-point.x);
Has anyone else run across this? How did you solve it? I'd rather not disable this warning or litter my code with a ton of typecasts.
I guess, you are using CGPoint types, so the conversion doesn't occur within fabs(DOUBLE -> FLOAT), but on assignment CGFloat = DOUBLE. That's probably because compiler used fabs from math.h which operates on doubles.
Problem with math.h is that it's internally imported by OSX headers (carbon if I remember correctly), so I guess some iOS header might also do that. After quick look, it seems that basic set of frameworks doesn't import math.h, so probably you should look for it being manually imported. In case it's imported internally by some system libs, you'll probably won't be able to use those libs and tgmath in a single implementation file.
If you want to check if there are some math.h dependencies, you can use a dirty trick to prevent it's inclusion - add this line to a file (or better on top of prefix file):
#define __MATH_H__
I was able to get the tgmath.h functions to work by including the header at the top of my PCH file.
At some point (read: Xcode update) I had to start disabling Modules to get this to work. The details of such are in the question Dima links to below.
I am trying to check if UIBarButtonSystemItemPageCurl exists on a given device.
Note: UIBarButtonSystemItemPageCurl exists on iOS 4.0 and above. I am also targeting iOS 3.1.3. Don't worry about the targeting iOS 3 part.
Currently tried:
if (UIBarButtonSystemItemPageCurl != NULL)
and
if ((UIBarButtonSystemItemPageCurl) == TRUE)
to check existence of the constant (Is UIBarButtonSystemItemPageCurl considered a constant? It's a value of typedef enum UIBarButtonSystemIcon). These two methods are currently not working. Can someone provide guidance on checking the existence a value of in a struct (not the containing struct)? Thanks.
If you look in UIBarButtonItem.h, you'll find that UIBarButtonSystemItemPageCurl is defined conditionally using the preprocessor:
typedef NS_ENUM(NSInteger, UIBarButtonSystemItem) {
⋮
#if __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
UIBarButtonSystemItemPageCurl,
#endif
};
…_MAX_ALLOWED is defined to the SDK version. Once the constant is defined, the constant always exists.
Comparing it against NULL is meaningless because this isn't a pointer. You are effectively comparing it against zero, and as it isn't the first thing in the enumeration, it isn't zero, so it is never NULL.
What it is is an integer. UIBarButtonSystemItemPageCurl is synonymous with 23, and the number 23 always exists, regardless of OS version.
So the question becomes “is UIBarButtonSystemItemPageCurl (a.k.a. 23) something that UIKit will recognize?”
One way to find that out would be to pass it to initWithBarButtonSystemItem:target:action: and see what happens. Hopefully, it will either return nil or throw an exception; either way, you can detect that and recover by doing whatever you need to do on iOS 3 devices.
Another way would be to ask the device for its systemVersion and compare it to #"4.0" in a way that understands version numbers. The Growl project has code for parsing and comparing version number strings. It's written for OS X, but should work with little to no modification on iOS.
I'd do the try-it-and-see approach first. Only if it silently fails (i.e., always returns a UIBarButtonItem, even on iOS 3, and the item you get on 3 just doesn't work) should you resort to comparing OS versions.