【问题标题】:Declaring ivars in superclass or @synthesize in subclass? [duplicate]在超类中声明 ivars 或在子类中声明 @synthesize? [复制]
【发布时间】:2013-08-07 15:32:29
【问题描述】:

当我只在超类中声明 @property 而不声明 ivars 时,将其子类化并尝试在子类中使用超类 ivar (_propertyName) 实现 getter,xcode 会调用错误声明 Use of undeclared identifier '_propertyName'。

符合最佳编程实践的解决方案是什么?

我应该在子类的@implementation中@synthesize propertyName = _propertyName还是

@interface SuperClass : AnotherClass
{
    Type *_propertyName;
}

@property Type *propertyName;

@end

编辑:
我确实了解属性访问器方法的自动“综合”以及编译器创建“下划线 ivars”。
ivar 可以从 SuperClass 的实现访问,而无需在接口或实现部分中声明任何 @synthesize 或 ivars 声明。

进一步澄清我的情况: 免责声明:内容从 Alfie Hanssen 窃取的代码块

@interface SuperViewController : UIViewController
@property (nonatomic, strong) UITableView * tableView; // ivar _tableView is automatically @synthesized
@end

#import "SuperViewController.h"

@interface SubViewController : SuperViewController
// Empty
@end

@implementation SubViewController

- (void)viewDidLoad
{
    NSLog(@"tableView: %@", self.tableView); // this is perfectly OK
}

// ************* This causes problem **************
- (UITableView *) tableView {
    if (!_tableView) {    // Xcode error: Use of undeclared identifier '_propertyName'
        _tableView = [[SubclassOfUITableView alloc] init];
    }
    return _tableView;
}
// ************************************************


@end

【问题讨论】:

  • 这很奇怪:在 Objective C 中,ivars 默认是受保护的,所以你的子类应该能够像访问它们一样访问它们。你如何访问_propertyName 来得到那个错误?
  • 如果您的属性是@property Type *_propertyName;,那么我认为ivar 将是__propertyName。 (两个下划线)为什么你的子类需要直接访问 ivar?
  • 仅供参考,不再需要@synthesize 属性;只需在头文件中声明它们,合成由 Xcode/编译器自动完成。
  • 抱歉,我更正了错字。 ivar 是自动创建的,但只能由超类直接访问。
  • @BergQuester 我在 SuperClass 中使用 ivar 来存储一个对象,该对象在子类的实现中是该对象的子类。

标签: objective-c properties subclass


【解决方案1】:

我根本不会访问 ivar。您想覆盖 getter,所以只需调用 super。

- (UITableView *)tableView {
    UITableView *tableView = [super tableView];
    if ( ! tableView) {
        tableView = [[SubclassOfUITableView alloc] init];
        self.tableView = tableView;
    }
    return tableView;
}

【讨论】:

  • 我应该提供更多代码。与我的情况类似,[super tableView] 将返回 (UITableView *)(alloced 和 inited) - 而不是 nil - 所以子类的吸气剂(可能)永远不会返回 SubclassOfUITableView。
  • 仍然,我根本不会访问 ivar。 如果你的两个 getter 都很懒,但它们返回不同类的 UITableView,那么创建方法 - (Class)tableViewClass 是覆盖它。总是有很好的解决方案。
【解决方案2】:

@synthesize 创建的 Ivar 是 @private。 (对于显式 @synthesize 语句和自动综合都是如此。)

您的类SuperViewController 确实有一个ivar _tableView,但它是@private,因此您的子类不能使用它。如果您需要一个子类可以使用的 ivar,则需要显式声明该 ivar 并将其设为 @private 以外的其他名称。 (您还想使用 @synthesize tableView=_tableView 以便该属性使用您声明的 ivar。)

【讨论】:

    【解决方案3】:

    显然 ivar 的自动合成在这种情况下不起作用。以下代码因编译器错误“使用未声明的标识符 _x”而失败,但仅适用于 JFNBclass。取消注释 ivar 声明,编译器错误就会消失。默认合成似乎不会创建继承类可见的 _x。

    JFNAclass.h

    #import <Foundation/Foundation.h>
    
    @interface JFNAclass : NSObject {
      // NSNumber *_x;
    }
    
    @property NSNumber *x;
    - (NSNumber *) xTest;
    
    @end
    

    JFNAclass.m

    #import "JFNAclass.h"
    
    @implementation JFNAclass
    
    - (NSNumber *) xTest
    {
      return _x;
    }
    
    @end
    

    JFNBclass.h

    #import <Foundation/Foundation.h>
    #import "JFNAclass.h"
    
    @interface JFNBclass : JFNAclass
    
    - (void) printIt;
    - (void) setIt;
    
    @end
    

    JFNBclass.m

    #import "JFNBclass.h"
    
    @implementation JFNBclass
    
    - (void) setIt
    {
        _x = [[NSNumber alloc] initWithInt:2];
    }
    
    - (void) printIt
    {
      NSLog(@"_x is %@", _x);
    }
    
    @end
    

    【讨论】:

    • 我没有运行那个测试... ... 结果与您引用的 SO 答案完全一致。奎尔惊喜!所以我赞成这个答案。
    • 很高兴你花时间写下来,我写下了几乎相同的代码。但如果你仔细阅读,我什至在标题中说明了这个解决方案。
    • 抱歉,您标题中的问号让我推断您对哪种技术可行有疑问。
    【解决方案4】:

    如果你想在超类和子类中都使用 ivar,你必须在超类的接口中声明它,因为它是唯一包含在两个实现中的文件。否则,您只是在猜测超类的实现可能是什么,而 xcode 将无法玩游戏。

    无论是否存在使用该 ivar 的属性,上述情况都是正确的。

    现在,如果您在超类中有一个属性并且您在子类实现中编写:

    @synthesize propertyName = _propertyName
    

    您只是说您正在放弃超类中该属性的任何实现,并且您想要由 xcode 生成的标准 setter 和 getter,在名为 _propertyname 的 ivar 上工作。也许超类的工作方式相同,也许不是。

    【讨论】:

      【解决方案5】:

      这应该可以正常工作。 self.tableView 和 _tableView 都应该可以从 SubViewController 访问。

      @interface SuperViewController : UIViewController
      @property (nonatomic, strong) UITableView * tableView; // ivar _tableView is automatically @synthesized
      @end
      
      #import "SuperViewController.h"
      
      @interface SubViewController : SuperViewController
      // Empty
      @end
      
      @implementation SubViewController
      
      - (void)viewDidLoad
      {
          NSLog(@"tableView: %@", self.tableView);
      }
      
      @end
      

      编辑: 好的,现在我明白你的问题更好了。看看这个question。似乎是重复的,似乎它回答了您的问题。 IE。看起来你必须明确定义实例变量。

      【讨论】:

      • 好的,如果我将这个方法添加到 SubViewController 实现中会怎样: - (UITableView *) tableView { if (!_tableView) { _tableView = [[SubclassOfUITableView alloc] init]; } 返回_tableView; }
      • “ivar _tableView 会自动 \@synthesized” 你怎么知道的?您假设 m 文件中没有 \@synthesize ,也没有 getter 或 setter 的自定义实现。你怎么知道?
      • 这不是该问题的重复,因为情况相反。我想要 ivar,我不必 synthesize 它,因为超类只实现 setter 并且属性是 readwrite - ivar 很容易从超类的实现中访问。
      猜你喜欢
      • 2015-07-10
      • 2020-09-12
      • 1970-01-01
      • 2013-11-19
      • 2017-03-12
      • 1970-01-01
      • 1970-01-01
      • 2014-03-23
      • 1970-01-01
      相关资源
      最近更新 更多