#ifdef __IPHONE_8_0 code runs also on iOS 7

2019-02-16 14:44发布

问题:

I've got the following code in my app - and I see some crashes on iOS 7 in the line with the comment.

+ (void)registerDeviceForRemoteNotifications {
#if !TARGET_IPHONE_SIMULATOR
    if ([[KOAAuthenticator sharedAuthenticator] currentUser] != nil) {
        UIApplication *sharedApplication = [UIApplication sharedApplication];
#ifdef __IPHONE_8_0
        [sharedApplication registerForRemoteNotifications]; // <--- CRASH HERE
#else
        [sharedApplication registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
#endif
    }
#endif
}

Crashlytics says: -[UIApplication registerForRemoteNotifications]: unrecognized selector sent to instance 0x157d04290

how's that even possible? This code shouldn't be called on iOS 7, right?

EDIT: solution

+ (void)registerDeviceForRemoteNotifications {
#if !TARGET_IPHONE_SIMULATOR
    if ([[KOAAuthenticator sharedAuthenticator] currentUser] != nil) {

        UIApplication *sharedApplication = [UIApplication sharedApplication];

#ifdef __IPHONE_8_0
        if ([sharedApplication respondsToSelector:@selector(registerForRemoteNotifications)]) {
            [sharedApplication registerForRemoteNotifications];
        } else {
            [sharedApplication registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
        }
#else
        [sharedApplication registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
#endif

    }
#endif
}

回答1:

Your code only adds support for compiling on an older version of Xcode and the iOS SDK.

You should add the following checks at runtime:

#ifdef __IPHONE_8_0
        if(NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) {
            [sharedApplication registerForRemoteNotifications]; // <--- CRASH HERE
        }
        else
#endif
        {
            [sharedApplication registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert];
        }


回答2:

An ifdef is evaluated at compile (or rather, preprocessing) time, not at runtime, so which one of the two registerForRemoteNotifications calls gets included in your built binary only depends on which SDK you build with, not what device it's run on.