On May 20, 2009, at 8:56 AM, Jonathan del Strother wrote:
I believe a short version of your question is: "How can I get multiple
inheritance?"  The short answer is that Objective-C does not support
multiple inheritance.
Yep. I know that, which is why I'm trying to find an elegant workaround.
Any solution I've missed?
Re-think your design so that the required ivars can be stored in a
delegate. If desired to make it more fool-programmer-proof and reuseable,
declare the delegate with an informal or formal protocol.
The problem there is that A doesn't have a delegate, and adding one requires
an ivar... back to square 1.

I'm trying to pretend I don't have access to the source for A, which would be the case for a Cocoa class for example. Let's pretend that :) Adding a 'delegate' ref would be just about acceptable, though it would be unused
entirely in the framework that provides the object.

One option (and I'm not saying it's a great one) is to add a category
to A, and fake ivars using a global dictionary.  The dictionary's keys
would be the object instances (or maybe an NSNumber created from the
instance address), and the dictionary's values would each be another
dictionary containing the instance's fake ivars.

Pretty unpleasant, just throwing it out there for consideration...

One would think that given the Objective-C 2.0 runtime (which is only available on iPhone OS, or 64-bit mode in Mac OS, ARGH!) and its support for iVar layouts, adding an ivar to an existing class would be possible. Since it isn't, you can do some disgusting, unsupported, nasty, evil, messed-up, and dangerous runtime tricks to "slip" a subclass into the inheritance hierarchy:

DISCLAIMER: The Objective-C runtime documentation specifically and explicity forbids doing this! Also, code written in Mail and completely untested.

// This version will automatically swizzle the subclass of A into place
// for every single existing subclass of A registered with the runtime.
BOOL    class_swizzleIntoPlaceGlobally(Class A, Class AA)
{
        // WARNING: This method will probably run very slowly
        if (class_getSuperclass(AA) != A) {
                return NO;
        }

        Class           *classList = NULL;
        int             classCount = 0;
        
        classCount = objc_getClassList(NULL, 0);
        classList = malloc(sizeof(Class) * classCount);
        if (!classList) {
                return NO;
        }
        classCount = objc_getClassList(classList, classCount);
        for (int i = 0; i < classCount; ++i) {
                if (class_getSuperclass(classList[i]) == A) {
                        // ALERT! ALERT! The Objective-C runtime docs
                        // specifically say NOT to do this!!
                        class_setSuperclass(classList[i], AA);
                }
        }
        return YES;
}

// This version does the same thing much more quickly, but requires you
// to know in advance which classes you want to swizzle.
// Example: class_swizzleIntoPlace([A class], [AA class], [B class], [C class], [D class], Nil); BOOL class_swizzleIntoPlace(Class A, Class AA, ...) NS_REQUIRES_NIL_TERMINATION
{
        if (class_getSuperclass(AA) != A) {
                return NO;
        }
        
        va_list         args;
        Class           cls = Nil;
        
        va_start(args, AA);
        cls = va_arg(args, Class);
        while (cls) {
                if (class_getSuperclass(cls) == A) {
                        // ALERT! ALERT! The Objective-C runtime docs
                        // specifically say NOT to do this!!
                        class_setSuperclass(cls, AA);
                }
        }
        return YES;
}

// AA.h
@interface AA : A
{
        int     theExtraIVarsGoHere;
}
+ (void)initialize;
- (void)theExtraMethodsGoHere;
@end

// AA.m
@implementation AA
+ (void)initialize
{
        if (!class_swizzleIntoPlaceGlobally(class_getSuperclass(self), self)) {
                // You probably want to do something more sensible here.
                abort();
        }
}

// ...
@end

-- Gwynne, Daughter of the Code
"This whole world is an asylum for the incurable."

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to