Search code examples
iosobjective-cnsmutabledictionary

how to override setObject: forKey: method (in Foundation Framework)


When Set nil value in dictionary then it is crashed. Below is the code.

NSMutableDictionary *dic = [@{} mutableCopy];
[dic setObject:nil forKey:@"test"];

this code will be crash. so is there a way to override setObject:forKey: to make it do not crash when nil is pass to it,just like this:[dic setObject:nil forKey:@"test"];

Can anyone help me to fix this problem?


Solution

  • If you use only NSString instances as keys, you can safely use next category from NSKeyValueCoding.h:

        @interface NSMutableDictionary<KeyType, ObjectType>(NSKeyValueCoding)
    
        /* Send -setObject:forKey: to the receiver, unless the value is nil, in which case send -removeObjectForKey:.
        */
        - (void)setValue:(nullable ObjectType)value forKey:(NSString *)key;
    
        @end
    

    If you want to use other types as keys, or avoid exception in case when key is nil, you can create your own category to NSMutableDictionary. For example:

        @interface NSMutableDictionary (CocoaFix)
    
        - (void)setObjectOrNil:(id)object forKeyOrNil:(id)key;
    
        @end
    
        @implementation NSMutableDictionary (CocoaFix)
    
        - (void)setObjectOrNil:(id)object forKeyOrNil:(id)key {
            if (object && key) {
                [self setObject:object forKey:key];
            }
        }
    
        @end
    

    Note that there is no way to override original setObject:forKey: method for NSMutableDictionary. Normally, method swizzling in categories can be used to do that. But NSMutableDictionary is actually the class cluster. Private subclasses of NSMutableDictionary do the real work under the hood. Each of subclasses has own setObject:forKey: implementation, because this method is primitive one. You can read more about class clusters at https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/ClassClusters/ClassClusters.html