【问题标题】:Calling `super` in Objective-C category在 Objective-C 类别中调用 `super`
【发布时间】:2016-10-16 14:38:21
【问题描述】:

我有一个名为Animal 的类,它是BaseEntity 的子类。我有一个名为CoreDataConversions 的协议,AnimalBaseEntity 都有符合的类别。在协议中我定义了一个方法:

- (instancetype)initWithManagedObject:(NSManagedObject *)managedObject dataManager:(id<DataManager>)dataManager

BaseEntity 类别很好地实现了这一点。然后,因为AnimalBaseEntity 的子类,所以我在动物类别中调用[super initWithManagedObject:managedObject dataManager:dataManager];

我收到一条消息崩溃:

[Animal setDataManager:] 无法识别的选择器发送到实例...

我在调用 super 时设置了一个断点并注销了以下内容:

po [self class] // Prints Animal

po [self superclass] // Prints BaseEntity

po [super class] // Prints Animal

po [super superclass] // Prints BaseEntity

那么:为什么Animal 类别的super 调用Animal,即使调用superclass 明确引用BaseEntity

编辑:

这是导致崩溃的代码:

- (id)insertEntityForClass:(Class)class
{
    if (![class conformsToProtocol:@protocol(CoreDataConversions)]) {
        return nil;
    }

    // A class method defined in CoreDataConversions
    NSString *entityName = [class coreDataEntityName];

    // Insert core data entity
    NSManagedObject *managedObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:self.currentMainContext];

    // Init with the managed object
    id entity = [[class alloc] initWithManagedObject:managedObject dataManager:self];

    return entity;
}

我有一个测试,它简单地调用Animal *animal = [dataManager insertEntityForClass:[Animal class]];,然后断言animal 的存在。

Animal 实现方法如下:

- (instancetype)initWithManagedObject:(NSManagedObject *)managedObject dataManager:(id<RHDataManager>)dataManager
{    
    self = [super initWithManagedObject:managedObject dataManager:dataManager];
    if (self) {
        // TODO
    }
    return self;
}

BaseEntity 实现了这样的方法:

- (instancetype)initWithManagedObject:(id)managedObject dataManager:(id<RHDataManager>)dataManager
{
    self = [super init];
    if (self) {
        self.dataManager = dataManager;
    }
    return self;
}

【问题讨论】:

  • 你能把崩溃的代码贴出来,说明它所在的类。只是为了让问题更清楚。
  • @danh 刚刚添加了有关崩溃的代码
  • 我可能很密集,但我在发布的代码中没有看到对 setDataManager 的调用
  • 是的,你是对的,事实证明它与属性声明有关。
  • 请注意,这种方法很容易陷入未定义的行为。类别不能覆盖超类的方法,如果两个类别实现相同的方法,则未定义调用哪一个。您并没有完全这样做,所以这是定义行为的最边缘。类别的重点是添加独立的功能,而不是参与继承。当涉及的类别覆盖您在此处执行的方式时,它有很多方法会巧妙地(并且令人惊讶地)出错。

标签: objective-c categories superclass super


【解决方案1】:

原来这实际上与属性声明有关。我在原始类中定义了readonly 属性,即@property (nonatomic, strong, readonly) id&lt;DataManager&gt; dataManager;

在类别中我已经重新定义了这样的属性:

@property (nonatomic, strong) id&lt;DataManager&gt; dataManager;

导致崩溃是因为在Animal 中没有为dataManager 设置setter,因为它仍在将其读取为readonly

【讨论】:

    猜你喜欢
    • 2010-12-07
    • 2019-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多