Re: Forcing allocation of a subclass
Re: Forcing allocation of a subclass
- Subject: Re: Forcing allocation of a subclass
- From: Jean-Daniel Dupas <email@hidden>
- Date: Sat, 24 Jan 2009 19:30:27 +0100
Le 24 janv. 09 à 19:20, Jean-Daniel Dupas a écrit :
Le 24 janv. 09 à 18:51, Antonio Nunes a écrit :
On 24 Jan 2009, at 18:09, Bill Bumgarner wrote:
Or, more specifically, why do you want to make some bit of
framework code which currently allocates an instance of A allocate
an instance of SubA instead?
Because of, what I assume to be, a bug in PDFClerkThumbnailView
which when one drags multiple pages from or within it, puts the
pages in a PDFDocument instead of in the subclass of PDFDocument,
which is where the pages live. Dragging a single page works as
expected and the page is of the correct subclass. Dragging multiple
pages leads to errors. I filed a bug report for this a while back,
but I really need a safe workaround until the issue is fixed.
(Assuming Apple considers it a bug too. I have never received
feedback on it.)
This is an excellent demonstration of why category based overrides
are rife with danger. The above code is making a boatload of
assumptions.
I know. That's why I wrote that I understand it is not the way to
go, but yet that it _appears_ to work.
I would use method_exchangeImplementations(), if absolutely
positively necessary. It is about the most innocuous of an
otherwise noxious encapsulation breaking implementation pattern.
Thanks. I found that a few hours ago and was able to create the
exchange. However, writing a correct replacement method is another
thing altogether. The following doesn't work:
Early in application startup:
Method originalMethod = class_getClassMethod([PDFDocument class],
@selector(alloc));
Method replacedMethod = class_getClassMethod([PDFDocument class],
@selector(allocReplacement));
method_exchangeImplementations(originalMethod, replacedMethod);
Addition to PDFDocument:
+ (id)allocReplacement
{
if ([[self class] isEqual:[PDFDocument class]]) {
return [ANPDFDocument alloc];
} else {
return [super alloc];
}
}
First, as it was said, the designated allocation method is
allocWithZone and not alloc.
Then, you call alloc in a recursive way in your method. alloc was
replaced by your allocReplacement, so calling alloc call
allocReplacement, even in you replacement implementation.
see http://developer.apple.com/samplecode/MethodReplacement/listing3.html
Then, alloc is a class method, so self is already the class. No need
to do [self class]
It should be
Method originalMethod = class_getClassMethod([PDFDocument class],
@selector(allocWithZone:));
Method replacedMethod = class_getClassMethod([PDFDocument class],
@selector(allocWithZoneReplacement:));
method_exchangeImplementations(originalMethod, replacedMethod);
+ (id)allocWithZoneReplacement:(NSZone *)aZone {
if (self == [PDFDocument class]) {
return [ANPDFDocument allocWithZoneReplacement:aZone];
} else {
return [super allocWithZoneReplacement:aZone];
}
}
Sorry, this is not
return [super allocWithZoneReplacement:aZone];
but
return [self allocWithZoneReplacement:aZone];
_______________________________________________
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