Objective-C: Compiler error when overriding a superclass getter and trying to access ivar

*爱你&永不变心* 提交于 2019-11-29 01:29:30
Josh Caswell

Synthesized ivars are not visible to subclasses, whether they are explicitly or automatically created: What is the visibility of @synthesized instance variables? Since they are effectively declared in the implementation file, their declaration isn't included in the "translation unit" that includes the subclass.

If you really want to access that ivar directly, you'll have to explicitly declare it (in its default "protected" form) somewhere that the subclass can see it, such as a class extension of the superclass in a private header.

There are a lot of posts on this topic on Stack Overflow, none of which offer simple concrete advice, but this topic sums it up most succinctly, and Josh's answer is the best in any.

What he kinda stops short of saying outright, is, if this is the kind of thing you want to do, don't use @property at all. Declare your regular protected variable in your base class as he says, and write you're own setters and getters if you need them. The ivar will be visible to any subclasses who can then write their own setters/getters.

At least that's where i've landed on the issue, although I'd a total newb to subclassing.

The idea of creating private headers to host your anonymous category and re-@sythesizing your ivars in your subclass just seems wrong on so many levels. I'm also sure I've probably missed some fundamental point somewhere.


Edit

Okay after some lost sleep, and inspired by Stanford's 2013 iTunes U course, here I believe is an example solution to this problem.

MYFoo.h

#import <Foundation/Foundation.h>

@interface MYFoo : NSObject
// Optional, depending on your class
@property (strong, nonatomic, readonly) NSString * myProperty;
- (NSString *)makeValueForNewMyProperty; //override this in your subclass
@end

MYFoo.m

#import "MYFoo.h"

@interface MYFoo ()
   @property (strong, nonatomic, readwrite) NSString * myProperty;
@end

@implementation MYFoo
// Base class getter, generic
- (NSDateComponents *)myProperty {
    if (!_myProperty) {
        _myProperty = [self makeValueForNewMyProperty];
    }
    return _myProperty;
}


// Replace this method in your subclass with your logic on how to create a new myProperty
- (NSString *)makeValueForNewMyProperty {
    // If this is an abstract base class, we'd return nil and/or throw an exception
    NSString * newMyProperty = [[NSString alloc]init];
    // Do stuff to make the property the way you need it...
    return newMyProperty;
}

@end

Then you just replace makeValueForNewMyProperty in your subclass with whatever custom logic you need. Your property is 'protected' in the base class but you have control over how it is created, which is basically what you are trying to achieve in most cases.

If your makeValueForNewMyProperty method requires access to other ivars of the base class, they will, at the very least, have to be be public readonly properties (or just naked ivars).

Not exactly 'over-ridding a getter' but it achieves the same sort of thing, with a little thought. My apologies if, in trying to make the example generic, some elegance and clarity has been lost.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!