macOS 15.2, strange runtime error on NSDictionary extension method

We are developing remote desktop app on macOS and recently got user's report about unexpected app crash on macOS 15.2 beta. On macOS 15.2, there's strange app crash on NSDictionary extension method.

We have narrowed down the steps and create the sample code to duplicate this issue.

  1. Create a cocoa app project in objective-c
  2. Try to access [NSNull null] value in NSDictionary
  3. Use specific method name for NSDictionary extension - (long long)longLongValueForKey:(NSString*)key withDefault:(long long)defaultValue;

The console output for the example app is like below, the method pointer seems to be wrong when trying to get value with longLongValueForKey:withDefault: method to a [NSNull null] object.

********* longLongValueForKey: a: 0 ********* longLongValueForKey: b: 100 ********* longLongValueForKey: c: 0 ********* longLongValueForKey:withDefault: a: -1 ********* longLongValueForKey:withDefault: b: 100 ********* exception: -[NSNull longLongValue]: unrecognized selector sent to instance 0x7ff8528d9760 ********* longLongValueForKey:withDefault1: a: -1 ********* longLongValueForKey:withDefault1: b: 100 ********* longLongValueForKey:withDefault1: c: -1

Please create an objective-c app project and add below code to reproduce this issue. // // AppDelegate.m // DictionaryTest // // Created by splashtop on 2024/11/13. //

#import "AppDelegate.h"

#define IsNullObject(id) ((!id) || [id isKindOfClass:[NSNull class]])

@interface NSDictionary (extension)

  • (long long)longLongValueForKey:(NSString*)key;
  • (long long)longLongValueForKey:(NSString*)key withDefault:(long long)defaultValue;
  • (long long)longLongValueForKey:(NSString*)key withDefault1:(long long)defaultValue;

@end

@interface AppDelegate ()

@property (strong) IBOutlet NSWindow *window; @end

@implementation AppDelegate

  • (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application

    NSDictionary* dict = @{ @"b" : @(100), @"c" : [NSNull null], };

    @try { long long a = [dict longLongValueForKey:@"a"]; NSLog(@"********* longLongValueForKey: a: %lld", a); long long b = [dict longLongValueForKey:@"b"]; NSLog(@"********* longLongValueForKey: b: %lld", b); long long c = [dict longLongValueForKey:@"c"]; NSLog(@"********* longLongValueForKey: c: %lld", c); } @catch(NSException* e) { NSLog(@"********* exception: %@", e); }

    @try { long long a = [dict longLongValueForKey:@"a" withDefault:-1]; NSLog(@"********* longLongValueForKey:withDefault: a: %lld", a); long long b = [dict longLongValueForKey:@"b" withDefault:-1]; NSLog(@"********* longLongValueForKey:withDefault: b: %lld", b); long long c = [dict longLongValueForKey:@"c" withDefault:-1]; NSLog(@"********* longLongValueForKey:withDefault: c: %lld", c); } @catch(NSException* e) { NSLog(@"********* exception: %@", e); }

    @try { long long a = [dict longLongValueForKey:@"a" withDefault1:-1]; NSLog(@"********* longLongValueForKey:withDefault1: a: %lld", a); long long b = [dict longLongValueForKey:@"b" withDefault1:-1]; NSLog(@"********* longLongValueForKey:withDefault1: b: %lld", b); long long c = [dict longLongValueForKey:@"c" withDefault1:-1]; NSLog(@"********* longLongValueForKey:withDefault1: c: %lld", c); } @catch(NSException* e) { NSLog(@"********* exception: %@", e); }

}

@end

@implementation NSDictionary (extension)

  • (long long)longLongValueForKey:(NSString*)key { long long defaultValue = 0; id value = [self objectForKey:key];

    if (IsNullObject(value) || value == [NSNull null]) { return defaultValue; } if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) { return [value longLongValue]; } return defaultValue;

}

  • (long long)longLongValueForKey:(NSString*)key withDefault:(long long)defaultValue { id value = [self objectForKey:key];

    if (IsNullObject(value) || value == [NSNull null]) { return defaultValue; } if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) { return [value longLongValue]; } return defaultValue;

}

  • (long long)longLongValueForKey:(NSString*)key withDefault1:(long long)defaultValue { id value = [self objectForKey:key];

    if (IsNullObject(value) || value == [NSNull null]) { return defaultValue; } if ([value isKindOfClass:[NSNumber class]] || [value isKindOfClass:[NSString class]]) { return [value longLongValue]; } return defaultValue;

}

@end

Answered by DTS Engineer in 814226022

It’s really hard to read your code snippets. Please post a new reply with your code formatted using a code block. See Quinn’s Top Ten DevForums Tips for advice on how to do that.

Having said that, using an Objective-C category to extend Apple types is a tricky business. The issue is that the methods added by your category might clash with methods added by Apple, or indeed by other developers. You need to add some sort of disambiguator to avoid such collisions.

If you add such a disambiguator, perhaps change the name from -longLongValueForKey:withDefault: to -QQQ_longLongValueForKey:withDefault:, does this problem go away?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

It’s really hard to read your code snippets. Please post a new reply with your code formatted using a code block. See Quinn’s Top Ten DevForums Tips for advice on how to do that.

Having said that, using an Objective-C category to extend Apple types is a tricky business. The issue is that the methods added by your category might clash with methods added by Apple, or indeed by other developers. You need to add some sort of disambiguator to avoid such collisions.

If you add such a disambiguator, perhaps change the name from -longLongValueForKey:withDefault: to -QQQ_longLongValueForKey:withDefault:, does this problem go away?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

macOS 15.2, strange runtime error on NSDictionary extension method
 
 
Q