Overlapping recipient properties with lazy loading in Objective-C

I usually lazy create @property objects in my getter methods, for example:

@interface MyGenericClass : UIViewController @property(nonatomic, readonly) UIImageView *infoImageView // ... @implementation GenericClass - (UIImageView *)infoImageView { if (!_infoImageView) { _infoImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"PlaceholderInfoImage"]]; } return _infoImageView; } 

But with subclasses, I often would like to redefine some of the @properties properties to be more specific subclasses. So I would like to change the instance and do something like:

 @interface MySpecificSubclass : MyGenericClass //... @implementation MySpecificSubclass - (UIImageView *)infoImageView { if (!_infoImageView) { _infoImageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"SpecialInfoImage"]]; } return _infoImageView; } 

But this is not possible because the subclass cannot access iVar _infoImageView.

Am I trying to make a bad style? Or is there a common solution / best practice for this? The only solution I see is to make iVar publicly available, which seems like a violation of encapsulation principles ...

It seems like this is such a very simple question that there are already millions of answers, but after searching for several hours, all I could find was Objective-C: The compiler failed to override the receiver of the superclass and tried to access ivar , but it doesn’t give solutions.

+7
source share
2 answers

You might want to declare _infoImageView as a protected variable in the header file along with the property. Another idea is to create a public defaultImageView method to call inside a lazy getter. Something like that:

 @interface MyGenericClass : UIViewController @property (nonatomic, readonly) UIImageView *infoImageView 

...

 @implementation GenericClass - (UIImageView *)infoImageView { if (!_infoImageView) { _infoImageView = [self defaultImageView]; } return _infoImageView; } - (UIImageView *)defaultImageView { return [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"PlaceholderInfoImage"]]; } 

...

 @interface MySpecificSubclass : MyGenericClass 

...

 @implementation MySpecificSubclass - (UIImageView *)defaultImageView { return [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SpecialInfoImage"]]; } 
+9
source

You can use the technique that the UIViewController uses for its view :

 - (UIView *)view{ if(!_view){ [self loadView]; NSAssert(_view, @"View must be set at end of loadView"); } return _view; } - (void)loadView{ // subclasses must set self.view in their override of this. NSAssert(NO, @"To be overridden by subclass"); } 
+4
source

Source: https://habr.com/ru/post/955592/


All Articles