【问题标题】:Overriding property getters with lazy loading in Objective-C在 Objective-C 中使用延迟加载覆盖属性获取器
【发布时间】:2026-01-20 10:25:01
【问题描述】:

我通常懒惰地在他们的 getter 方法中实例化我的 @property 对象,如下所示:

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

@implementation GenericClass

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

但是当子类化时,我经常想覆盖一些@properties 以使其更具体。所以我想更改实例化并执行以下操作:

@interface MySpecificSubclass : MyGenericClass
//...

@implementation MySpecificSubclass

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

但这是不可能的,因为子类无法访问 _infoImageView iVar。

是我想要做的不好的风格吗? 或者是否有一个通用的解决方案/最佳实践?我看到的唯一解决方案就是将 iVar 公开,这感觉就像违反了封装原则……

感觉这是一个非常基本的问题,肯定已经有数百万个答案,但搜索了几个小时后,我只能找到Objective-C: Compiler error when overriding a superclass getter and trying to access ivar ,但它没有提供任何解决方案。

【问题讨论】:

    标签: objective-c properties overriding lazy-loading lazy-initialization


    【解决方案1】:

    您可能希望将_infoImageView 与属性一起声明为头文件中的受保护变量。 另一个想法是创建一个公共的defaultImageView 方法来调用惰性getter。 像这样的:

    @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"]];
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用UIViewController 用于其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");
      }
      

      【讨论】: