Objective C class inheritance with factory methods

2019-04-29 04:48发布

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?

3条回答
Anthone
2楼-- · 2019-04-29 05:07

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.

查看更多
我只想做你的唯一
3楼-- · 2019-04-29 05:19

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 UIImages and CGImages are immutable. This should not result result in a deep copy of the image data.

查看更多
爱情/是我丢掉的垃圾
4楼-- · 2019-04-29 05:23

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];
查看更多
登录 后发表回答