10

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
}
swalkner
  • 16,679
  • 31
  • 123
  • 210
  • the _compiler time_ and _runtime_ are two different things... – holex Aug 14 '14 at 08:23
  • I know; but I guess this should work - on iOS 8 and later the ```registerForRemoteNotifications``` whould be called, otherwise ```registerForRemoteNotificationTypes``` - right? – swalkner Aug 14 '14 at 08:38
  • 2
    no. that decision is made in _compiler time_. if the base SDK iOS8, then that method will be compiled into your binary: `–registerForRemoteNotifications`, if the base SDK iOS7, then this will be compiled in to your binary: `–registerForRemoteNotificationTypes:`. in that case it is irrelevant what the _runtime_ environment will be later, because the macros are _complier time_ features, they are not connected to the _runtime_ at all on any level. – holex Aug 14 '14 at 09:11
  • I guess that's not true. If base SDK iOS8, the if-else-part is compiled in the binary. If base SDK iOS7, the ```registerForRemoteNotificationTypes:``` is compiled into the binary. – swalkner Aug 14 '14 at 10:30

2 Answers2

15

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];
        }
Léo Natan
  • 56,823
  • 9
  • 150
  • 195
5

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.

Léo Natan
  • 56,823
  • 9
  • 150
  • 195
mstorsjo
  • 12,983
  • 2
  • 39
  • 62