What you want to do is fundamentally impossible. Don't forget that this:
@property(strong) AbstractPage *page;
declares a getter and a setter.
Generally speaking (this is for OO programming generally, not just Objective-C), there is no problem with an override getter returning a subclass of the return type of the super class implementation because this does not break the API contract. In your case, an instance of WhitePage
is also an AbstractPage
.
However, the setter is different. You can't restrict the type of the parameter because your subclass must be useable anywhere where an AbstractBook
is used, so code that invokes the setter on something that it thinks is an AbstractBook
is entitled to pass in an instance of any AbstractPage
subclass, because that is what the API says.
I think what I would do is add a method to AbstractBook
called something like
-(bool) isLegalPage: (AbstractPage) aPage;
that returns true always in the base class but true only for white pages in WhiteBook
. Then I would manually implement the setter as follows:
-(void) setPage: (AbstractPage*) aPage
{
if (![self isLegalPage: aPage])
{
// throw an exception or do other error notification
}
else
{
Do the assignment according to reference count/ARC/GC model
}
}
Document that the setter will throw an exception if the page is not legal and that people should use the isLegalPage:
method to test this.
The alternative id to have a read only property and use different setters in the base class and subclass, or don't have a setter at all in the base class.