Archivio dicembre, 2009

Objective-C: esporre proprietà in una classe

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
// MyClass.h
#import <Foundation/Foundation.h>

@interface MyClass : NSObject {
    NSString *nome;
    NSString *cognome;
}

@property (retain) NSString *nome;
@property (retain) NSString *cognome;
@end

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
#import <Foundation/Foundation.h>

@interface MyClass : NSObject {
    NSString *_nome;
    NSString *_cognome;
}

- (NSString *) nome;                               // get
- (NSString *) cognome;                            // get

- (void) setNome: (NSString *)stringaIngresso;     // set
- (void) setCognome: (NSString *)stringaIngresso;  // set

@end

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;
}

Ulteriore variante

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.

Allocazioni di memoria

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… :)

Continua...

Browser o Mobile Browser?

Il nostro sito Web ormai non è visualizzato solo da postazioni PC. Con la diffusione del mobile, grazie soprattutto ad Apple iPhone, l’accesso al sito o blog viene sempre più spesso effettuato da dispositivi mobili di vario tipo. Diventa quindi esigenza di molti Web Developer saper intercettare ed identificare i diversi “agenti”, cioè gli strumenti con cui un utente visualizza (naviga) le nostre pagine.

Continua...

Personalizzare graficamente un Form

Mi è stato chiesto come personalizzare graficamente un form, in particolare un form di ricerca come quello presente su questo blog. La tecnica utilizzata, o meglio che utilizzo io, è ovviamente valida per qualsiasi tipo di modulo form. Quello che cambia è solo la complessità del lavoro da svolgere in funzione della complessità del form stesso.

Continua...

WordPress: visualizzare gli ultimi topic di bbPress

Abbiamo visto come integrate il kernel di WordPress in bbPress, per usare ad esempio qualche funzione WordPress o condividere il tema. Ora vedremo il contraio, cioè come mostrare le informazioni del forum bbPress nella Home Page di WordPress. Per fare questa operazione esistono alcuni Plugin (alcuni funzionanti e altri no). Noi qui vedremo invece come scrivere una – davvero – semplice funzione che, in caso, può essere migliorata e perfezionata per tutti i casi.

Continua...

Apple iPhone: creare un custom toggle button

Gli stati UIControlStateSelected o UIControlStateHighlighted non funzionano quando un UIButton è impostato in modalità UIButtonTypeCustom! O meglio, non funzionano come dovrebbero (perchè riservati agli altri tipi di bottone), ad esempio per creare un bottone a due stati: toggle appunto. Se abbiamo creato due immagini (stato1.png e stato2.png) per il nostro bottone, possiamo procedere in questo modo:

1
2
3
// Nell'header file creiamo una variabile globale che usaremo per
// controllare il toggle state
BOOL toggleFlag;

Ora creiamo il nostro bottone:

1
2
3
4
5
6
7
8
9
// Creaiamo un bottone e lo poniamo inizialmente nello stato "stato1.png"
// Modificate initWithFrame:(CGRect){100,100,50,50} con la posizione e
// dimensioni della vostra immmagine
toggleFlag = YES;
UIButton *toggleButton = [[UIButton buttonWithType:UIButtonTypeCustom] initWithFrame:(CGRect){100,100,50,50}];
[toggleButton setTitle:@"" forState:UIControlStateNormal];
[toggleButton setBackgroundImage:[UIImage imageNamed:@"stato1.png"] forState:UIControlStateNormal];
[toggleButton addTarget:self action:@selector(onToggle:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:toggleButton];

Quando si clicca sul bottone verrà inviato un messaggio gestito da onToggle:

1
2
3
4
5
6
7
- (void)onToggle:(id)sender {
// Recupero puntatore al UIButton
UIButton *buttonClicked = (UIButton *)sender;
// Eseguo il toogle
toggleFlag = !toggleFlag;
[buttonClicked setBackgroundImage:[UIImage imageNamed:(toggleFlag) ? @"stato1.png" : @"stato2.png"] forState:UIControlStateNormal];
}

Continua...

Very short snippet: streaming mp3 file su Apple iPhone

Un’alternativa davvero semplice per eseguire uno streaming di un file mp3 su Apple iPhone potrebbe essere:

Continua...


Stop SOPA