iPhone: l’utilissima proprietà tag

Tutti gli oggetti che derivano dalla classe <a target="_blank" href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/cl/UIView">UIView</a>, ereditano l’utilissima proprietà <a target="_blank" href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816-CH3-SW25">tag</a>. Questa proprietà è un vero e proprio user-data (un “posto” che lo sviluppatore usa per usi generici) di tipo <a target="_blank" href="http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_DataTypes/Reference/reference.html#//apple_ref/doc/c_ref/NSInteger">NSInteger</a>, dove quindi possiamo memorizzare esclusivamente numeri.

L’uso che se ne può fare dipende ovviamente dalle circostanze tuttavia risulta utilissimo per individuare un determinato oggetto allo scattare di un evento comune. Ad esempio immaginiamo di avere due <a target="_blank" href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIAlertView_Class/UIAlertView/UIAlertView.html">UIAlertView</a> che rispondono allo stesso evento:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// primo alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Primo" message:@"Primo Alert" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil,nil];
[alert show];
[alert release];

// ...

// secondo alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Secondo" message:@"Secondo Alert" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil,nil];
[alert show];
[alert release];

// Evento
// Cliccandi sul bottone OK degli Alter verrà chiamata questa funzione
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    // todo
}

Nota: negli esempi di codice troverete l’indicazione C++. Questo non è del tutto corretto in quanto, come saprete, il linguaggio usato è Objective-C. Questo a causa del fatto che il Plugin che uso per visualizzare il codice sorgente non supporta Objective-C, e il C++ è quello che meglio gli si avvicina.

Come distinguere i due Alert? Utilizzando appunto la proprietà tag. Dopo la creazione dell’oggetto alert basta inserire:

1
2
3
4
5
6
7
8
9
10
11
12
13
// primo alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Primo" message:@"Primo Alert" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil,nil];
[alert setTag:1]; // imposto il tag di questo Alert ad 1
[alert show];
[alert release];

// ...

// secondo alert
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Secondo" message:@"Secondo Alert" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil,nil];
[alert setTag:2]; // imposto il tag di questo Alert ad 2
[alert show];
[alert release];

Ora modifichiamo l’evento in modo da capire quale Alert è stato chiuso:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Evento
// Cliccandi sul bottone OK degli Alter verrà chiamata questa funzione
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    switch (alertView.tag) {
        case 1:
            // Primo Alert
            break;
        case 2:
            // Secondo Alert
            break;
        default:
            break;
    }
}

Stessa identica tecnica può essere utilizzata se abbiamo una serie di <a target="_blank" href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIButton_Class/UIButton/UIButton.html">UIButton</a> creati runtime. Ad esempio:

1
2
3
4
5
6
7
8
9
10
for( unsigned int i=0; i < 10; i++) {
    UIButton *mybutton = [[UIButton buttonWithType:UIButtonTypeCustom] initWithFrame:CGRectMake(i*20, i*20, 20, 20)];
    [mybutton setTitle:@"But" forState:UIControlStateNormal];
    [mybutton setTag:i]; // imposto il tag

    // stesso evento per tutti
    [mybutton addTarget:self action:@selector(onTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:mybutton];
}

Nell’evento onTouchUpInside recuperiamo dal sender (dove eseguiamo un casting <a target="_blank" href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/cl/UIView">UIView</a>) la proprietà <a target="_blank" href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816-CH3-SW25">tag</a>:

1
2
3
4
-(void)onTouchUpInside:(id)sender {
    unsigned int button_tag = ((UIView *)sender).tag;
    // todo
}

2 commenti a: “ ”

  1. 12 giu, 2009 Andrea Leganza:

    Non si deve abusare della proprietà tag (ovviamente non è questo il caso) quando si è in situazioni in cui una view è molto struttura, che ha quindi x subview, poichè tale elenco viene gestito con un NSArray, questo viene scansito allo scopo di trovare tale tag.
    Se la ricerca viene effettuata confrontando numericamente i tag sequenzialmente (e non credo che non venga fatto in altro modo, al massimo ordinano internamente per tag le subview)

    objectatindex non è realmente così ma l’ho messo per semplicità per far capire la semantica.

    1
    2
    3
    4
    5
    ciclo scansione subviews {
       if (self.subviews.objectatindex(i).tag == tagrichiesto) {
               return self.subviews.objectatindex(i);
       }
    }

    1) nel caso migliore il tag è il primo quindi abbiamo effettuato un confronto
    2) in un caso mediano avremo n confronti
    3) nel caso peggiore, che non esista, avremo effettuato per ogni iterazione x confronti inutili

    Viene spesso utilizzato per accedere alle celle delle tabelle, e in questa situazione, dove possiamo avere centinaia di righe con x subview per riga che si ha il massimo spreco (se sono 100 celle con ognuna 10 subviews ipotizzando il caso peggiore del non trovato: avremo effettuato 100*10=1000 confronti inutili, per non parlare di invocazioni in cascata all’array subview e ai vari metodi di analisi).

  2. 12 giu, 2009 Andrea Leganza:

    Dimenticavo… in alcune situazioni è forse consigliabile usare un iboutlet se usiamo IB (interface builder) oppure avere una serie di proprietà associate a tali oggetti, ai quali potremo accedere direttamente da qualunque metodo della nostra classe; il confronto se è un oggetto o un altro in questo caso si può fare semplicemente utilizzando l’operatore == visto che confrontiamo gli indirizzi fisici dei due oggetti (più veloce di così non si può).
    Nell’esempio mostrato ovviamente va benissimo, alla fine si effettua un confronto tra “interi” all’interno dello switch; ma ho visto molti utilizzare/abusare dei tag per evitare di aggiungere variabili locali.

    buona programmazione

Lascia un commento

TAG XHTML PERMESSI: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> INSERIMENTO CODICE:
<pre></pre> // blocco generico
                   <code></code> // blocco generico
                   [cc_actionscript][/cc_actionscript] // Actionscript
                   [cc_actionscript3][/cc_actionscript3] // Actionscript 3
                   [cc_css][/cc_css] // CSS Style Sheet
                   [cc_html][/cc_html] // HTML
                   [cc_js][/cc_js] // Javascript
                   [cc_objc][/cc_objc] // Objective-C
                   [cc_php][/cc_objc] // PHP
                   [cc_sql][/cc_sql] // SQL