Reputation: 449
If we want to override [dictionary objectForKey:@"key"]
it can be done by subclassing NSDictionary
class. How to override dictionary[@"key"]
? In this context I want to know how dictionary[@"key"]
is implemented.
Thanks!
Edit:
I wanted to find a scalable way to parse an API response while preventing [NSNull null]
from crashing my app. I have written category for NSDictionary
, but I wanted a way to parse in this syntax: data[@"key"]
So, I was evaluating the feasibility of subclassing NSDictionary
.
Upvotes: 0
Views: 1561
Reputation: 6635
EDIT: This question is pretty old now, but it just recently came to my attention again, so I thought I would add an example of wrapping NSDictionary
as I would recommend. This could be made more robust and feature rich, but it's an okay place to start.
@interface NilSafeDictionary: NSObject
-(instancetype)initWithDictionary:(NSDictionary*)dictionary;
@end
/** Category on NSDictionary to create a nil-safe wrapper. */
@interface NSDictionary <NilSafeConvenience>
- (NilSafeDictionary*)nilSafe;
@end
@implementation NilSafeDictionary {
NSDictionary* _internalDict;
}
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
self = [super init];
if (self) {
_internalDict = [dict copy];
}
return self;
}
- (id)objectForKeyedSubscript:(id<NSCopying>)key {
id obj = _internalDict[key];
if ([obj isKindOfClass:[NSNull class]]) {
return nil;
}
return obj;
}
@end
@implementation NSDictionary <NilSafeConvenience>
- (NilSafeDictionary*)nilSafe {
return [[NilSafeDictionary alloc] initWithDictionary:self];
}
@end
CAVEAT: You don't explain here what problem you're trying to solve, but for anyone who comes across this question in the future, subclassing
NSDictionary
is almost certainly never what you want.
NSDictionary is a class cluster. Class clusters are tricky to subclass correctly with guidance, plus Apple's documentation explicitly tells you not to subclass, so there's no guidance on how to do it correctly.
Even if you're able to use your subclass and have it "work correctly" for your purposes, every other piece of code in the system will still be returning the original NSDictionary
class, not your subclass, so it doesn't benefit you.
If you're hell bent on modifying the way NSDictionary
works, create your own wrapper class that has an NSDictionary
inside and create your own objectForKeyedSubscript:
implementation.
Yes, you can add subscript indexing to your own custom class just like NSDictionary
!
Upvotes: 1
Reputation: 3424
dictionary[@key]
is short hand for calling [dictionary objectForKeyedSubscript:@"key"]
. Therefore to override the functionality of dictionary[@"key"]
you can subclass NSDictionary
.
@interface MyDictionary : NSDictionary
- (id) objectForKeyedSubscript:(id)key;
@end
@implementation MyDictionary
- (id) objectForKeyedSubscript:(id)key
{
/*
...
*/
}
@end
Original answer using categories, however this approach isn't advised as it will override the original method removing access to super
and potential of clashes should multiple categories be loaded overriding the same method. The last category to be loaded will be used at runtime, therefore you cannot guarantee which that will be.
dictionary[@key]
is short hand for calling [dictionary objectForKeyedSubscript:@"key"]
. Therefore to override the functionality of dictionary[@"key"]
you would create a new category for NSDictionary
.
//Category in NSDictionary+CustomKeyedSubscript.h and NSDictionary+CustomKeyedSubscript.m
@interface NSDictionary (CustomKeyedSubscript)
- (id) objectForKeyedSubscript:(id)key;
@end
@implementation NSDictionary (CustomKeyedSubscript)
- (id) objectForKeyedSubscript:(id)key
{
/*
...
*/
}
@end
Upvotes: 0
Reputation: 8345
When you use dictionary[@"key"]
this gets converted into a call to [dictionary objectForKeyedSubscript:@"key"]
. objectForKeyedSubscript:
has the same behaviour as objectForKey:
.
If you want to change the behaviour of dictionary[@"key"]
then you will need to override objectForKeyedSubscript:
.
Apple's NSDictionary API Reference has a little more information.
Upvotes: 2