C'è una classe che assomiglia a questo (sto omettendo le importazioni per brevità):Override proprietà di sola lettura nella sottoclasse
Base.h:
@interface Base : NSObject
@property (strong, readonly) NSString *something;
- (id)initWithSomething:(NSString *)something;
@end
Base. m:
@implementation Base
- (id)initWithSomething:(NSString *)something {
self = [super init];
if (self) _something = something;
return self;
}
@end
Come si vede, la proprietà 'qualcosa' è di sola lettura. Ora voglio creare una sottoclasse che sostituisce quella proprietà per essere scrivibile così:
Sub.h:
@interface Sub : Base
@property (strong) NSString *something;
@end
Sub.m:
@implementation Sub
@end
E il codice:
main.c:
int main(int argc, const char * argv[]) {
@autoreleasepool {
Sub *o = [Sub new];
o.something = @"foo";
NSLog(@"%@", o.something);
}
return 0;
}
Questo codice si traduce in:
2013-09-07 13:58:36.970 ClilTest[3094:303] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason: '-[Sub setSomething:]: unrecognized
selector sent to instance 0x100109ff0'
Perché? Perché non trova setSelector?
Quando faccio questo nella sottoclasse invece:
Sub.m:
@implementation Sub
@synthesize something = _something;
@end
funziona il tutto. Significa che la proprietà della sottoclasse non è sintetizzata per impostazione predefinita anche se è definita come @property
nello @interface
? La compilazione in qualche modo 'vede' il getter generato automaticamente da Base e non genera il setter? E perché, penso che il setter dovrebbe essere generato perché non esiste ancora. Sto usando Xcode 4.6.2 e il progetto è uno strumento Cli (tipo Foundation), ma lo stesso accade nel mio progetto attuale che è un'app per iPhone.
Sfondo: Ho un oggetto pesante (istanza di Base) che richiede una connessione Bluetooth ad alcune apparecchiature e dovrei creare un controller di visualizzazione per alcune funzionalità. Per test facili non voglio essere connesso a BT (in realtà, avrei bisogno di un dispositivo fisico e testare il codice su di esso), mi piacerebbe poterlo testare nel simulatore. Quello che mi è venuto in mente è che semplicemente creo una sottoclasse (Sub) che stuba alcuni metodi/proprietà e la uso invece, e quando il codice è pronto rimuovo solo il codice per la sottoclasse, sostituisco l'istanza con quella corretta , prova con un dispositivo, commetti e spinge. Funziona davvero bene, tranne che per la cosa strana con @property
sopra.
Qualcuno potrebbe dirmi che cosa sta succedendo con la proprietà prioritaria?
Oltre alla soluzione di lavoro, volevo aggiungere che "aumentare" il livello di privacy di un attributo va contro i principi OOP. Di solito (ma non sempre), se devi rendere una proprietà più visibile (privata -> protetta, o, protetta -> pubblica) in una sottoclasse, allora qualcosa non va nel modello. L'opposto accade con i metodi. Se la classe genitore ha il metodo A, non devi rendere A più privato (pubblico -> protetto, o, protetto -> privato) in una sottoclasse. –