I would like to inherit from a framework class that has a factory method. How can I make the factory method return an object of my inherited class type? I found this useful article which describe a similar situation but in their case you have control over the superclass. How could I write, say, a subclass of UIImage
that imageNamed:
would return an object of my subclass type?
问题:
回答1:
I would like to inherit from a framework class that has a factory method. How can I make the factory method return an object of my inherited class type?
This is all you should have to do:
@interface MONImage : UIImage
@end
@implementation MONImage
@end
Then:
MONImage * image = [MONImage imageNamed:name];
How could I write, say, a subclass of UIImage that imageNamed: would return an object of my subclass type?
+[UIImage imageNamed:]
's implementation wrote subclassers out of this approach. Consequently, you would need to implement this method yourself.
Here's how one should declare a factory method:
+ (instancetype)imageNamed:(NSString *)pName;
and how one should implement it:
+ (instancetype)imageNamed:(NSString *)pName
{
MONImage * image = [[self alloc] initWithThisDesignatedInitializer:pName];
^^^^ NOTE: self, not a concrete class
...set up image...
return image;
}
but they did not do it that way -- +[UIImage imageNamed:]
wrote subclasses out and returns a UIImage
when you write MONImage * img = [MONImage imageNamed:pName];
. Sometimes that is done for a good reason. Some methods should have 'final' semantics. This often appears when your method may return multiple types, as in a class cluster. The language does not express 'final' methods -- but such a method should at least be documented.
So to come around to this UIImage
case:
@interface MONImage : UIImage
+ (instancetype)imageNamed:(NSString *)pName;
@end
@implementation MONImage
+ (instancetype)imageNamed:(NSString *)pName
{
UIImage * source = [UIImage imageNamed:pName];
CGImageRef cgImage = source.CGImage;
if (cgImage)
return [[self alloc] initWithCGImage:cgImage];
// try it another way
return nil;
}
@end
Note that UIImage
s and CGImage
s are immutable. This should not result result in a deep copy of the image data.
回答2:
For your example:
- Subclass
UIImage
to, say,MyImage
- Implement the
imageNamed:
method to do anything specific that you need to be done. - Call that method on that class:
MyImage *newImage = [MyImage imageNamed:imageName];
回答3:
The approach that solved my problem was to use a category instead of inheritance (credits go to Jonathan Cichon in the comments of my question). I used Associative References to declare and store additional data in the category implementation as discussed a lot here in SO. I would like to drive the attention to the NSObject
category implementation proposed by Jonathan that makes really easy and elegant to add associative references to any object.