Objective-C: ошибка компилятора при переопределении получателя суперкласса и попытка доступа к ivar

Я работаю над созданием приложения iOS 6.

У меня есть класс TDBeam, который наследуется от суперкласса TDWeapon.

Суперкласс TDWeapon объявляет @property в файле TDWeapon.h:

@interface TDWeapon : UIView

@property (nonatomic) int damage;

@end

Я не явно @synthesize свойство, поскольку я позволяю Xcode автоматически делать это.

В подклассе TDBeam я переопределяю getter в файле TDBeam.m:

#import "TDBeam.h"

@implementation TDBeam

- (int)damage {
    return _damage;
}

@end

Xcode автоматически завершает имя метода getter, как и ожидалось. Но когда я пытаюсь ссылаться на переменную экземпляра _damage (унаследованную от суперкласса), я получаю ошибку компилятора:

Use of undeclared identifier '_damage'

Что я здесь делаю неправильно? Я попытался явно добавить @synthesize и изменить имя _damage ivar, но компилятор не "видит" его или любые другие ivars из суперкласса. Я думал, что ивары были видны и доступны из подклассов?

Ответы

Ответ 1

Синтезированные ivars не видны для подклассов, независимо от того, были ли они явно или автоматически созданы: Какова видимость переменных экземпляра @synthesized? Поскольку они эффективно объявлены в файл реализации, их декларация не включена в "блок переводов", который включает подкласс.

Если вы действительно хотите получить доступ к этому ivar напрямую, вам придется явно объявить его (в его защищенной форме по умолчанию) где-нибудь, что подкласс может его увидеть, например расширение класса суперкласса в закрытом заголовке.

Ответ 2

В Qaru много сообщений по этой теме, ни одна из которых не предлагает простых конкретных советов, но этот вопрос суммирует ее наиболее кратко, а ответ Josh - лучший в любом случае.

То, что он вроде бы перестает говорить прямо, есть, если это то, что вы хотите сделать, вообще не используйте @property. Объявите свою обычную защищенную переменную в своем базовом классе, как он говорит, и напишите, что вы являетесь собственными сеттерами и получателями, если они вам понадобятся. Ивар будет виден всем подклассам, которые затем могут писать свои собственные сеттеры/геттеры.

По крайней мере, когда я приземлился на проблему, хотя у меня был бы общий newb для подкласса.

Идея создания закрытых заголовков для размещения вашей анонимной категории и повторной фильтрации ваших ivars в вашем подклассе просто кажется неправильной на столь многих уровнях. Я также уверен, что я, вероятно, пропустил какой-то фундаментальный момент.


Изменить

Хорошо после некоторого потерянного сна, и вдохновленный курс iTunes UT в Stanford 2013, здесь я считаю, что это пример решения этой проблемы.

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

Затем вы просто замените makeValueForNewMyProperty в своем подклассе на любую настраиваемую логику, в которой вы нуждаетесь. Ваша собственность "защищена" в базовом классе, но у вас есть контроль над тем, как она создается, и это в основном то, чего вы пытаетесь достичь в большинстве случаев.

Если ваш метод makeValueForNewMyProperty требует доступа к другим ivars базового класса, они, по крайней мере, должны быть общедоступными свойствами readonly (или просто голыми ivars).

Не совсем "избыточное избавление от геттера", но он достигает такого же уровня, с небольшой мыслью. Приношу свои извинения, если, пытаясь сделать пример родовым, теряется какая-то элегантность и ясность.