Re: Can a subclass of NSDictionary do this?
Re: Can a subclass of NSDictionary do this?
- Subject: Re: Can a subclass of NSDictionary do this?
- From: Greg Titus <email@hidden>
- Date: Tue, 22 Jul 2003 16:11:06 -0700
On Tuesday, July 22, 2003, at 03:36 PM, James Quick wrote:
I was implementing a subclass of NSObject which contained an
NSMutableDictionary.
The purpose is to support a storage container for nested
NSDictionaries to allow me to
search by keys having internal structure.
for a call [self lookup: k inDict: d]
The key@ "a.b.c" would do the following
lookup: k inDict: d
v = [d objectForKey: @"a"]
if ([v isKindOfDictionary])
return [self lookup: @"b.c" inDict: d]
else return v;
this would reduce to looking up @"c" in the subdictionary @"a.b"
Thus a single call to lookup would traverse a path through the set of
nested dictionaries to find a value.
This is built in actually. Look at the documentation for
NSKeyValueCoding. Specifically, you'll get exactly the result you want
by calling [d valueForKeyPath:@"a.b.c"].
If this didn't already exist, the best way to implement it would be the
way Apple did it: as a category on existing classes. If you find
yourself wanting to add methods but not instance variables to a class
(or classes) writing categories should almost always be your first
choice.
Then I encountered some documentation that made me wonder.
The documentation for NSDictionary states:
"NSDictionary's three primitive methods- count, objectForKey:, and
keyEnumerator-provide the basis for all of the other methods in its
interface."
The NSMutableDictionary documentation declares:
"With its two efficient primitive methods- setObject:forKey: and
removeObjectForKey:-this class adds modification operations to the
basic operations it inherits from NSDictionary."
This made me wonder if I could simply override 5 methods, with
recursive implementations
and be able to make use of all the other functionality of those
classes for free!
Yes, you can, but it usually isn't recommended. Read the documentation
on "Class Clusters".
Imagine that I have a subclass of NSDictionary which declares no new
instance variables
overrides objectForKey. Lets call this RDict for recursive dict. and
Dict for an NSDictionary
Is there way via casting, or other mild chicanery, to cause a vanilla
NSDictionary or
NSMutableDictionary instance to rely on my implementation of a few
methods,
and have the rest handled by calls to super?
You'd do this via -poseAs:. (NSObject documentation.)
I could then take dictionaries loaded by CFPreferences, for instance
and
get the recursive path lookups for nearly no work. Simply by tricking
them
temporarily into thinking they were instances of my class.
I thought of categories but I would prefer another approach, because I
don't want to
impose the added overhead on all instances of NSDictionary.
There is absolutely no added overhead with categories.
Would [((MyClass *)plainClass) objectForKey] start its method lookup
in the isa of MyClass or the isa of [plainClass class].
Casting Obj-C objects does nothing. It compiles into no code and
doesn't change the semantics at all. The only reason why it is useful
is to tell the compiler that you are doing something, so that it knows
whether to give you warnings about messages going to wrong classes and
the like.
Or could I safely do (yes I know this looks scary)
Class * cheatLikeHell(struct objc_object *object, Class *otherclass)
{
Class *oldClass = object->isa;
object->isa = otherclass;
return oldClass;
}
Class *customClass = [MyRecursiveDictionary class];
Class *savedClass = cheatLikeHell(normalDictionary, customClass);
[normalDictionry doStuff]; // now using my implementation
(void) cheatLikeHell(normalDictionary, savedClass);
Yes, you could, but it is _so_ much simpler to just add a category with
a -myDoStuff method and call that instead.
Hope this helps,
- Greg
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.