2

after update to Xcode6, I got this code crash on IOS 7 with "Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings", can any one help with it

if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]){
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:  (UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert) categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    [[UIApplication sharedApplication] registerForRemoteNotifications];
}
else {
    int notifyType = (UIRemoteNotificationTypeAlert |
                      UIRemoteNotificationTypeBadge |
                      UIRemoteNotificationTypeSound);
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)notifyType];
}

EDIT : hi all, it's a runtime crash, not a compile time link error,

Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000000e7ffdefe Triggered by Thread: 0

Dyld Error Message: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings

and I was on Xcode 6.0 (6A313), So I should not use any #if to indicator iOS versions. And this code works fine on IOS 8 simulator, but crashes on IOS 7 devices

EDIT 2 :

Finally, this issue was fixed by these codes, I have mark the right answers below, thanks trojanfoe.

    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)])
{
    Class userNotifyClass = NSClassFromString(@"UIUserNotificationSettings");
    if(userNotifyClass != nil)
    {
        id notifyInstance = [userNotifyClass settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:nil];
        [application registerUserNotificationSettings:notifyInstance];
        [application registerForRemoteNotifications];
    }
}
else
{
    int notifyType = (UIRemoteNotificationTypeAlert |
                      UIRemoteNotificationTypeBadge |
                      UIRemoteNotificationTypeSound);
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)notifyType];
}
wangsihao
  • 23
  • 6

5 Answers5

2

I think you are building your project with 'base SDK' 7.x So you could change it to 8.0 or check current version during compilation:

#if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1       

    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:  (UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert) categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    [[UIApplication sharedApplication] registerForRemoteNotifications];
#else
    int notifyType = (UIRemoteNotificationTypeAlert |
                      UIRemoteNotificationTypeBadge |
                      UIRemoteNotificationTypeSound);
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)notifyType];
#endif
Shmatlay Andrey
  • 212
  • 4
  • 13
1

Works for me on XCode 6.1 @ iOS 8 SDK / iOS 7 deployment target. My app uses -ObjC linker flag as well.

Just ran app on iPhone with iOS 7.1.2 / ARMV7. I use the following code:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    if([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:nil];
        [application registerUserNotificationSettings:notificationSettings];
        [application registerForRemoteNotifications];
    } else {
        [application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
    }
    return YES;
}

Update: additionally tested on iPad 4 / iOS 8, iPhone 5s / iOS 8. All work fine.

pronebird
  • 12,068
  • 5
  • 54
  • 82
1

change UIKit.framework to optional works to me

change UIKit.framework to optional works to me

Ping
  • 145
  • 2
  • 6
0

UIUserNotificationSettings is available only on iOS8

if(NSClassFromString(@"UIUserNotificationSettings") != nil) 
{
    //do your stuff here
} 
Grzegorz Krukowski
  • 18,081
  • 5
  • 50
  • 71
0

You must be compiling with an iOS SDK version less than 8 in order to get that link error.

To fix the issue use the iOS 8 SDK (i.e. Xcode 6) and check that the class exists at runtime using:

if (NSClassFromString(@"UIUserNotificationSettings")) {
    // do thing
}

EDIT After further information from the OP:

  • He is using Xcode 6 and the iOS 8 SDK.
  • He is using the -ObjC and -all_load Other Linker Flag.

It's the -ObjC/-all_load flags that stops the usual techniques of testing for a class to exist at runtime and using it selectively.

In order for the app to support iOS 7 and iOS 8 with -ObjC semantics, I can think of two solutions:

  • Remove the use of -ObjC/-all_load linker flags in favour of -force_load, as that targets a specific library for "all load" (see my question here).
  • Use a more dynamic (and error prone) approach of:

    1. Creating an instance of UIUserNotificationSettings using NSClassFromString().
    2. Calling methods with performSelector.

I would favour the first approach.

Community
  • 1
  • 1
trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • hi, it's a runtime crash, something "weak link", not a compile time error – wangsihao Sep 23 '14 at 08:17
  • @wangsihao Are you using the `-ObjC` *Other Linker Flag*? – trojanfoe Sep 23 '14 at 08:20
  • hi trojanfoe, I finally solve this problem by the second approach you motioned "Use a more dynamic (and error prone) approach of". I will put my code in the question's edit section. Thanks. – wangsihao Sep 24 '14 at 02:36