Question

I have an abstract interface in Objective-C where every sub-class needs to set up a property and then do the exact same thing with that property at the end of init. I'm trying to avoid duplicated code with something like this:

Interface File

@interface Shape : NSObject

@property (nonatomic) PropertyType *prop;

- (id)init;
- (void)initProperty;

@end

Implementation File

@implementation Shape

- (id)init
{
    if(self = [super init]) {
        [self initProperty];
        [prop doSomething];
    }
    return self;
}

- (void)initProperty
{
}

@end

My problem is that every sub-class will need a different set of parameters passed to initProperty in order to implement the method correctly:

@implementation Rectangle

- (void)initPropertyWithRect:(CGRect)rect
{
    prop = [RectangleStuff rectangleWithRect:rect];
}

@end

@implementation Circle

- (void)initPropertyWithRadius:(CGFloat)radius
{
    prop = [CircleStuff circleWithRadius:radius];
}

@end

Is there a clean way to do what I'm trying to do in Objective-C? So far, my options seem to be:

  1. Create a "property bag", and just pass around an NSDictionary.
  2. Duplicate the [property doSomething]; code in every subclass.
  3. Somehow pass in a factory object to init, and have the factory object create prop. This approach seems the cleanest, but I'd need the factory object to keep the rect and/or radius as internal state somehow, and that doesn't seem clean to me.

Any thoughts?

Was it helpful?

Solution

I would probably choose #2 (to keep it simple). If the property is only set once (in the subclass init method), you could override the property setter method in the superclass, and do the additional stuff there.

Untested code:

- (void)setProp:(PropertyType *)prop
{
    _prop = prop; // (Assuming ARC)
    [_prop doSomething];
}

OTHER TIPS

First, I feel obligated to mention that your init function should not do anything besides initialize the object. That said, every rule has a time and a place to be broken, so I'll offer what suggestions I can.

Your init function is no different than any other function. You can do things before and after you call super. While generally discouraged, this would be a good place to do it. Your init in your subclass would now look like this:

- (id)init
{
    self.myProperty = value;
    self = [super init];
    if (self) {
        // more init stuff
    }
    return self;
}

I ended up using a variant of what was suggested in the other two answers:

Shape.h

@interface Shape : NSObject

@property (nonatomic) PropertyType *prop;

- (id)initWithProperty:(PropertyType *prop);

@end

Shape.m

@implementation Shape

- (id)initWithProperty:(PropertyType *)prop
{
    if(self = [super init]) {
        _prop = prop;
        [_prop doSomething];
    }
    return self;
}

@end

Rectangle.m/Circle.m

@implementation Rectangle

- (void)initWithRect:(CGRect)rect
{
    return [self initWithProperty:[RectangleStuff rectangleWithRect:rect]];
}

@end

@implementation Circle

- (void)initWithRadius:(CGFloat)radius
{
    return [self initWithProperty:[CircleStuff circleWithRadius:radius]];
}

@end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top