problem with subclassing a cluster class
problem with subclassing a cluster class
- Subject: problem with subclassing a cluster class
- From: Ivan Kourtev <email@hidden>
- Date: Sun, 5 Mar 2006 15:18:30 -0500
Hi,
I want to subclass NSDictionary so that I can override -
(NSScriptObjectSpecifier *)objectSpecifier to make my app
scriptable. I understand that NSDictionary is a class cluster so I
follow the prescriptions in Apple's document "Cocoa Objects", the
chapter on class clusters. I am trying to use the "Composite Object"
pattern (to be honest, I didn't fully understand the difference
between this and the "True Subclass" pattern because they are both
derived from the cluster so seem like subclasses).
At any rate, my problems seem to arise from the fact that I want to
initialize an instance of my subclass with the variadic function +
(id)dictionaryWithObjectsAndKeys:(id)firstObject, ...
From everything I have read and tried, it appears that I cannot
simply pass the arg list of a variadic function to another variadic
function within it. So I went for something like the code attached
at end -- compiles with no warnings but I get an *** Uncaught
exception: <NSInternalInconsistencyException> *** -[NSCFDictionary
setObject:forKey:]: mutating method sent to immutable object at runtime.
So I try changing NSDictionary to NSMutableDictionary and things only
start working somewhat when I also derive MyDictionary from
NSMutableDictionary. But now I get runtime errors like *** Uncaught
exception: <NSInvalidArgumentException> *** -count only defined for
abstract class. Define -[MyDictionary count]! and I keep fixing them
but a new one keeps popping in (count, keyEnumerator, etc.)
Is the overriding of all these methods something I really should do
or am I missing something here? In rereading the Apple doc
referenced above "Since the cluster’s abstract superclass is the only
publicly visible node in the cluster’s hierarchy, the first point is
obvious. This implies that the new subclass will inherit the
cluster’s interface but no instance variables, since the abstract
superclass declares none. Thus the second point: The subclass must
declare any instance variables it needs. Finally, the subclass must
override any method it inherits that directly accesses an object’s
instance variables. Such methods are called primitive methods." so
may be I should really redefine all primitive classes?
But then, two other points in question:
1. How does one tell which methods of a class cluster are primitive
and which aren't?
2. Assuming I pulled it off, my non-mutable dictionary class is still
based on NSMutableDictionary which just doesn't seem right? This
feels like a contradiction to me -- there has to be a more elegant
solution here that I can't see. Help anyone?
Cheers,
-- ivan
#import <Foundation/Foundation.h>
@interface MyDictionary : NSDictionary { NSDictionary
*embeddedDictionary; }
- (id)init;
+ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...;
@end
@implementation MyDictionary
- (id)init
{
self = [super init];
if ( self ) {
embeddedDictionary = [[NSDictionary alloc] init];
}
return self;
}
+ (id)dictionaryWithObjectsAndKeys:(id)firstObject, ...
{
// argument list empty: not much to do but return an empty
dictionary
if ( firstObject == nil ) {
return [[[self alloc] init] autorelease];
}
// arguments exist: create dictionary and insert keys and
objects from list
id dictionary = [[self alloc] init];
va_list argList;
id anObject, aKey;
va_start( argList, firstObject );
aKey = va_arg(argList, id);
NSLog( @"The first object from the argument list is %@",
firstObject );
NSLog( @"The next object from the argument list is %@", aKey );
if ( aKey == nil ) {
NSLog( @"Invalid arg list to %s", __PRETTY_FUNCTION__ );
assert( NO );
} else {
NSLog( @" Now inserting %@ for key %@", firstObject, aKey );
[dictionary setObject:firstObject forKey:aKey];
}
while ( ( anObject = va_arg( argList, id) ) != nil ) {
aKey = va_arg( argList, id);
if ( aKey == nil ) {
NSLog( @"Invalid arg list to %s", __PRETTY_FUNCTION__ );
assert( NO );
} else {
NSLog( @" Now inserting %@ for key %@", anObject, aKey );
[dictionary setObject:anObject forKey:aKey];
}
}
va_end( argList );
return [dictionary autorelease];
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *obj = [NSString stringWithString:@"myObject"];
NSString *key = [NSString stringWithString:@"myKey"];
MyDictionary *dict = [MyDictionary
dictionaryWithObjectsAndKeys:obj, key, nil];
NSLog( @"Created dictionary: %@", dict );
[pool release];
return 0;
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden