Property inheritance

  • Here's my class graph:

    Shape (base class - inherits only from NSObject)
    LineShape : Shape
    RectangleShape : Shape
    SquareShape : RectangleShape

    In RectangleShape, I define:

    @property (nonatomic, assign) CGSize rectSize;
    @property (nonatomic, readonly) CGFloat area;
    @property (nonatomic, readonly) CGFloat perimeter;

    and in RectangleShape.m, I implement these manually, except for rectSize, which I @synthesize:

    ...
    #pragma mark - Non-synthesized accessors

    -(CGFloat)area
    {
    return (self.rectSize.width * self.rectSize.height);
    }

    -(CGFloat)perimeter
    {
    return (self.rectSize.width * 2.0 + self.rectSize.height * 2.0);
    }
    // other stuff...
    ...

    I now want SquareShape to also have the 'area' and 'perimeter' properties, but these should be read/write as there's a direct correlation between the area and the side of the square; ditto for the perimeter. If a subclass (SquareShape) redefines the @property in a superclass as readwrite, are there any 'gotcha's I need to watch out for?

    i.e.

    SquareShape.h
    #import "RectangleShape.h"

    @interface SquareShape : RectangleShape

    @property (nonatomic, readwrite, assign) CGFloat area;
    @property (nonatomic, readwrite, assign) CGFloat perimeter;

    @end

    SquareShape.m
    #import "SquareShape.h"

    @implementation SquareShape

    #pragma mark - Non-synthesized accessors

    -(CGFloat)area
    {
    return (self.rectSize.width * self.rectSize.height);
    }

    -(void)setArea:(CGFloat)area
    {
    CGFloat sideLength = sqrt(area);
    CGSize squareSize = CGSizeMake(sideLength, sideLength);
    self.rectSize = squareSize;
    }

    -(CGFloat)perimeter
    {
    return (self.rectSize.width * 2.0 + self.rectSize.height * 2.0);
    }

    -(void)setPerimeter:(CGFloat)perimeter
    {
    CGFloat sideLength = perimeter / 4.0;
    CGSize squareSize = CGSizeMake(sideLength, sideLength);
    self.rectSize = squareSize;
    }

    @end
  • On Jul 4, 2012, at 9:32 AM, William Squires wrote:

    > Here's my class graph:
    >
    > Shape (base class - inherits only from NSObject)
    > LineShape : Shape
    > RectangleShape : Shape
    > SquareShape : RectangleShape

    Just so you know, this is the archetypal example of a violation of the Liskov substitution principle. <https://en.wikipedia.org/wiki/Liskov_substitution_principle#A_typical_viola
    tion
    >  The problem is that you can't pass a SquareShape to code which is expecting a RectangleShape because such code is entitled to do things like set rectSize to non-square dimensions.

    > If a subclass (SquareShape) redefines the @property in a superclass as readwrite, are there any 'gotcha's I need to watch out for?

    No.  This is an intended use case. <https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Obje
    ctiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW19
    >

    > @implementation SquareShape
    >
    > #pragma mark - Non-synthesized accessors
    >
    > -(CGFloat)area
    > {
    > return (self.rectSize.width * self.rectSize.height);
    > }
    > …
    > -(CGFloat)perimeter
    > {
    > return (self.rectSize.width * 2.0 + self.rectSize.height * 2.0);
    > }

    It shouldn't be necessary to re-implement the getters.  If the compiler complains – I don't think it should – then you can quiet it with "@dynamic area, perimeter;".

    Regards,
    Ken
previous month july 2012 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Go to today