Uno dei vantaggi dei file Property list, che altro non sono che file testuali che seguono lo standard XML, è quello di poter essere trasformati istantaneamente in oggetti (come array o dictionary) Objective-C. Quando si crea un file Property list:

Uno dei vantaggi dei file Property list, che altro non sono che file testuali che seguono lo standard XML, è quello di poter essere trasformati istantaneamente in oggetti (come array o dictionary) Objective-C. Quando si crea un file Property list:

Se ci si trova a sviluppare in un ambiente dove è impossibile usare tool di debug come FireBug, come ad esempio il simulatore Apple iPad di Xcode, può diventare frustante individuare problemi, uno tra tutto l’errato accesso alle proprietà di un oggetto. Ecco che l’uso della funziona alert() diventa fondamentale!
In Objective-C abbiamo due modi molto utilizzati per ricevere ed inviare messaggi tra classi: le notifiche e i delegati. La differenza tra i due, oltre che essere a livello di implementazione, dipende sostanzialmente da “quanti” – oggetti – possono ricevere un messaggio. Prima di tutto lasciatemi mostrare come nasce il concetto di delegato.
Anche nei tutorial più semplici è possibile incontrare l’uso dei protocolli. Sarà certamente capitato a molti di utilizzare nel vostro view controller un protocollo, inserendo, accanto alla definzione dell’interfaccia, una dicitura simile a:
1 2 3 | @interface myViewController : UIViewController <uiwebviewdelegate> { ... } |
Vorrei mostrare e discutere alcuni esempi sul come aggiungere e manipolare proprietà in una Classe Objective-C. Un esempio classico, per l’appunto, è il seguente; nella definizione della nostra interfaccia di classe definiamo due proprietà nome e cognome:
1 2 3 4 5 6 7 8 9 10 11 |
Nel file di implementazione inseriamo la dichiarazione @synthesize in modo tale che Xcode produca per noi i metodi getter e setter usati rispettivamente per leggere ed impostare le nostre due proprietà:
1 2 3 4 5 6 7 8 | // MyClass.m #import "MyClass.h" @implementation MyClass @synthesize nome, cognome; @end |
Quando andremo ad utilizzare la nostra classe MyClass, cioè quando istanziaremo un oggetto di tipo MyClass, possiamo scrive:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // qualsiasi altra classe, come AppDelegate // nel file .h #import <UIKit/UIKit.h> #import "MyClass.h" @class TestViewController; @interface TesAppDelegate : NSObject <UIApplicationDelegate> { UIWindow *window; TestViewController *viewController; MyClass *miaClasse; } // nel file .m miaClasse = [MyClass alloc]; miaClasse.nome = @"Giovambattista"; NSLog(@"miaClasse.nome = %@", miaClasse.nome); |
Oppure, che è equivalente:
1 2 3 | // sempre nel file .m [miaClasse setNome:@"Undolog"]; NSLog(@"miaClasse.nome = %@",[miaClasse nome]); |
Fin qui tutto bene. Tuttavia potrebbe fuorviare l’equivalenza delle “variabli” interne (ivar) con il nome della proprietà vera e propria. Per capire la differenza, ripropongo lo stesso esempio facendo a meno, questa volta, di @synthesize. Ora, quindi, dovremmo occuparci noi di scrivere i metodi getter e setter. Per sottolineare ulteriormente le differenze, rinominerò le variabili interne inserendo un underscore davanti al nome. Ma vediamo il codice:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
A differenza dell’esempio precedente i puntatori alla variabili interne (incapsultate) sono diventati _nome e _cognome. Inoltre troviamo quattro definizioni di metodi che rappresentano le nostre get e set. @property è scomparso, in quanto non serve più.
Vediamo il file di implementazione MyClass.m:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #import "MyClass.h" @implementation MyClass // get per "nome" - (NSString *) nome { return _nome; } // set per "nome" - (void) setNome: (NSString *)stringaIngresso { _nome = stringaIngresso; } // get per "cognome" - (NSString *) cognome { return _cognome; } // set per "cognome" - (void) setCognome: (NSString *)stringaIngresso { _cognome = stringaIngresso; } @end |
Una classe così scritta potrà essere utilizzata esattamente come la precedente, cioè:
1 2 3 4 5 6 7 8 | miaClasse = [MyClass alloc]; miaClasse.nome = @"Giovambattista"; NSLog(@"miaClasse.nome = %@", miaClasse.nome); // Oppure, che è equivalente: [miaClasse setNome:@"Undolog"]; NSLog(@"miaClasse.nome = %@",[miaClasse nome]); |
A livello didattico l’abbandono di @synthesize ci ha costretto a scrivere “da soli” i metodi di get e set, evidenziando – anche con l’aggiunta dell’underscore – le differenze tra il nome della proprietà e la sua ivar interna _nome.
A livello funzionale l’uso dei metodi personali get e set permette un reale controllo del dato prima della sua impostazione (o prima della sua lettura) e quindi un reale incapsulamento per proteggere la variabile interna.
Ad esempio sarebbe possibile impedire il passaggio di stringhe vuote alla proprietà nome:
1 2 3 4 | - (void) setNome: (NSString *)stringaIngresso { if( stringaIngresso == @"" ) stringaIngresso = @"senza nome"; _nome = stringaIngresso; } |
Se desiderate utilizzare le variabili interne con l’underscore davanti (chi rpoviene da Adobe Actionscript potrebbe essere abituato così) non è necessario abbandonare l’uso della direttiva @synthesize. Xcode permette infatti di “fondere” i metodi sopra indicati:
1 2 | @synthesize nome = _nome; @synthesize cognome = _cognome; |
Così facendo potremmo usare internamente il puntatore a _nome, “sintetizzato” – verso l’esterno – come proprietà nome. Inoltre, se è vero che l’uso di @synthesize produce la generazione automatica dei metodi (messaggi) di getter e setter, è vero anche che lo fa solo se non li trova, quindi se desiderate “implementare” un vostro metodo di getter e/o setter potete farlo anche se avete usato la direttiva @synthesize.
Negli esempi di sopra ho omesso alcuni dettagli importanti ai fini di una reale implementazione. Prima di tutto non ho illustrato nessun metodo init(), utile ai fini dell’inizializzazione dell’oggetto e dei sui valori di default. Inoltre, manca l’aggiunta di un metodo dealloc():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | // file MyClass.m #import "MyClass.h" @implementation MyClass - (id) init { if ( self = [super init] ) { _nome = @"Nome preimpostato"; _cognome = @"Cognome preimpostato"; } return self; } - (void) dealloc { [_nome release]; [_cognome release]; [super dealloc]; } - (NSString *) nome { return _nome; } - (void) setNome: (NSString *)stringaIngresso { if( stringaIngresso == @"" ) stringaIngresso = @"senza nome"; _nome = stringaIngresso; } - (NSString *) cognome { return _cognome; } - (void) setCognome: (NSString *)stringaIngresso { _cognome = stringaIngresso; } @end |
In futuro vedremo poi i dettagli sulle proprietà readonly, retain, etc…
Nel Post Estendere i MovieClip in Adobe Flash MX avevo illustrato alcune tecniche per estendere un MovieClip. In particolare avevo detto che l’uso di MovieClip.prototype non permetteva l’estensione di proprità ma solo di metodi:
[...] Due importanti limitazioni di questa tecnica sono:
- Non può essere applicata a tutti gli oggetti esposti da Flash
- Possono essere “aggiunti” solo metodi e non proprietà [...]
In verità è possibile, con un passaggio in più, aggiungere dinamicamente proprietà anche usando MovieClip.prototype. Prima dell’introduzione di function get e function set, infatti, Flash permetteva l’aggiunta di proprietà (in lettura/scrittura o solo lettura) tramite il metodo addProperty(). Nella pratica questo si traduce nell’invocazione del metodo addProperty() e nella definizione di due funzioni getter e setter. La setter può essere null così da creare proprietà in sola lettura. Ad esempio se volessimo estendere tutti i MovieClip con una nuova proprietà _alpha in grado di aggiungere un’animazione, basta scrivere il seguente codice:
1 2 3 4 5 6 7 |
Da questo momento in poi se abbiamo un simbolo “miosimbolo_mc” possiamo sfruttare questa nuova proprietà:
1 | miosimbolo_mc._alpha_tween = 50; |
Quello che non è possibile fare, invece, è sovrascrivere le proprietà esistenti; per questo motivo ho usato _alpha_tween invece di _alpha. Ecco, quindi, un buon motivo per usare comunque le Classi 2.0 per estendere – e derivare – eventuali MovieClip.
Ultimi Commenti
Giovambattista Fazioli: @ale: Come indicato @Kevin vedi sul repo di GitHub: https://github.com/gfazioli/Ch roma-Key
Giovambattista Fazioli: @Kevin: See https://github.com/gfazioli/Ch roma-Key
Kevin: Very nice example – would like to see the .fla too!
Ludovica: Ciao! Ti spiego il mio dubbio. Quando scrivo un post non inserisco immagini nell’articolo (se così...
Marco: ciao @Giovambattista Fazioli, grazie per tutte le delucidazioni di questa ottima guida. Avrei un quesito da...