I am running into a weird issue when trying to test for the existence of a symbol that is introduced in a newer version of the OS. I follow the Apple guidelines on using weak-linked symbols, i.e.
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.
To reproduce the issue, I am using the latest iOS 6 SDK on the latest Xcode 4.5.2, using the default compiler (Apple LLVM compiler 4.1). I weak-linked the Social framework (which is only available on iOS 6+). And I run this code on iOS 5.1 (the deployment target is lower than 6):
NSLog(@"%p", &SLServiceTypeFacebook);
if (&SLServiceTypeFacebook)
NSLog(@"Yes1");
if (&SLServiceTypeFacebook != NULL)
NSLog(@"Yes2");
The output is:
0x0
Yes1
Yes2
In other words, we can verify at runtime that the expression &SLServiceTypeFacebook
evaluates to the value 0. Yet, if
statements that test on this expression treat it as if it is true.
Update: From this question, I found that this workaround works with no optimization, but not with optimization:
typeof(&SLServiceTypeFacebook) foo = &SLServiceTypeFacebook;
if (foo)
NSLog(@"Yes3"); // does not get executed on -O0, but does on any optimization
Update: It appears that this problem does not exist with UIKit symbols. Running the following on iOS 4.3:
NSLog(@"%p", &UIKeyboardDidChangeFrameNotification);
if (&SLServiceTypeFacebook)
NSLog(@"Yes1");
if (&SLServiceTypeFacebook != NULL)
NSLog(@"Yes2");
The output is:
0x0
I hypothesize that the difference is that the UIKit symbol has a NS_AVAILABLE_IOS()
macro next to it, so somehow the compiler handles it correctly. In the case of the Social framework symbol, it doesn't have a NS_AVAILABLE_IOS()
macro since the entire Social framework itself is only available since iOS 6 (i.e. the symbol is available since the version of the framework, so I guess the don't need this macro?); but then the compiler does not handle the symbol correctly.