Есть два способа сделать это.Ни в том, ни в другом случае вы не вызываете @synthesize
в подклассе. Я удивлен, что компилирует для вас.Я ожидаю ошибку типа «Свойство n1» при попытке использовать ivar «_n1», объявленную в суперклассе «A» ». В любом случае это определенно не то, что вы действительно можете сделать, поэтому вы видите странное поведение,(Я вспомнил, почему вы не видите эту ошибку; это из-за отдельных модулей компиляции. Вы просто получаете разные ивары.)
Во-первых, вам нужно понять @dyanmic
.Это способ сказать компилятору: «Да, я знаю, что вы не видите здесь реализацию требуемого метода; я обещаю, что он будет там во время выполнения».В подклассе вы будете использовать @dynamic
, чтобы сообщить компилятору о том, что унаследовать n1
.
@implementation B
@dynamic n1;
@end
нормально. Теперь вам нужно предоставить метод setN1:
.IMO, подклассы не должны портиться с иварами их суперклассов, поэтому я одобряю тот факт, что синтезированные ивары отмечены @private
.Через секунду я расскажу вам, как отменить это, но сейчас давайте разберемся с моим предпочтительным решением:
- Реализация
setN1:
как частного метода в A
. - Выставить его в
B
.
А *
@interface A : NSObject
@property (readonly) int n1;
- (void) display;
@end
Am
#import "A.h"
@interface A () // Private class extension, causes setN1: to be created but not exposed.
@property (readwrite) int n1;
@end
@implementation A
@synthesize n1 = _n1;
- (void) display {
...
}
@end
Bh
#import "A.h"
@interface B : A
@property (readwrite) int n1; // Tell the world about setN1:
@end
Bm
#import "B.h"
@implementation B
@dynamic n1; // Yes compiler, setN1: exists. I promise.
@end
Теперь некоторые люди считают, что для подклассов нормально связываться с иварами их суперкласса.Эти люди не правы (хорошо, ИМХО ...), но это возможно в ObjC.Вам просто нужно объявить ивар @protected
.Это значение по умолчанию, когда вы объявляете ivars непосредственно в @interface
(одна из многих причин, по которой вам больше не следует делать это).Это выглядело бы так:
Ах
@interface A : NSObject {
int _n1;
}
...
Am - убрать дополнительное расширение класса, которое делает n1 доступным для записи в суперклассе.
Bh - без изменений
Bm
@implementation B
@dynamic n1;
- (void)setN1:(int)n1 {
_n1 = n1;
}
@end