Re: Sensible way to extend base class?
Re: Sensible way to extend base class?
- Subject: Re: Sensible way to extend base class?
- From: Gwynne Raskind <email@hidden>
- Date: Wed, 20 May 2009 11:08:10 -0400
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 (email@hidden)
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:
This email sent to email@hidden