Weak linking on iPhone refuses to work
Asked Answered
C

2

19

I've got an iPhone app that's mainly targetting 3.0, but which takes advantage of newer APIs when they're available. Code goes something like this:

if (UIApplicationDidEnterBackgroundNotification != NULL) {
    [nc
        addObserver: self
        selector:    @selector(irrelevantCallbackName:)
        name:        UIApplicationDidEnterBackgroundNotification
        object:      nil];
}

Now, according to everything Apple's ever said, if the relevant APIs are weakly linked, that will work fine because the dynamic linker will evaluate UIApplicationDidEnterBackgroundNotification to NULL. Except that it doesn't. The application compiles, but as soon as it hits if (UIApplicationDidEnterBackgroundNotification != NULL) it crashes with EXC_BAD_ACCESS.

Is this simply a matter of a compiler flag I need to set? Or am I going about this the wrong way?

Chronon answered 9/6, 2010 at 2:53 Comment(2)
I knew I would find the answer by merely searching for UIApplicationWillEnterForegroundNotification on SO… It must be the most common reason for developers to need to deal with conditionally available globals.Baobaobab
@Pierre Lebeaupin: That seems to be the case.Chronon
C
38

Aaand I figured it out. For symbols that are not functions (extern const int foobar, for instance), you have to compare against the address of the symbol, not the symbol itself, so:

if (&UIApplicationWillEnterForegroundNotification != NULL)
    etc;

Which in retrospect is kind of obvious, but I still fault the entire universe around me for not ever mentioning the distinction.

Chronon answered 9/6, 2010 at 2:59 Comment(2)
If you are using LLVM, you have to do some tricks to get it to not optomize out your if statement. This works for me. BOOL backgroundOK = &UIApplicationDidEnterBackgroundNotification != NULL; if (backgroundOK) { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification bject:nil]; }Flinch
Using vanilla GCC, but if LLVM is looking at it differently, I suspect it may be a bug on Apple's part (as Apple explicitly tells developers to do this sort of runtime check with weak-linked symbols.) You might want to write up a test case and submit it to Apple at bugreporter.apple.com . :)Chronon
S
5

Here is what I had to do when checking for an external framework constant.

const CLLocationAccuracy * ptr = &kCLLocationAccuracyBestForNavigation;
BOOL frameworkSupports = (ptr != NULL);
if (frameworkSupports) {
    return kCLLocationAccuracyBestForNavigation;
} else {
    return kCLLocationAccuracyBest;
}

It would not work without the ptr variable.

Siding answered 23/8, 2010 at 19:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.