Nella guida di oggi approfondiremo un componente molto utilizzato all’interno delle applicazioni per iphone, stiamo parlando di UIPickerView (e UIDatePicker).
Lo studio di questi due oggetti ci permetterà di chiarire il concetto di delegate e di vedere all’opera il paradigma mvc (model-view-controller)
Diamo un’occhiata alla gerarchia delle classi per capire di cosa ci occupiamo oggi:


Gerarchia delle classi UIPickerView e UIDatePicker


Come nostra consuetudine i nomi bordati in verde si riferiscono a classi già trattate su questo stesso sito [qui], mentre quelli bordati in rosso sono quelle che analizzeremo in questo articolo.

Concorderete con me che non c’è sistema migliore per studiare una classe se non quella di scaricare la class reference dal sito della apple, (ok, ok, a parte leggere il sorgente :) ) ecco quindi due link per un facile download:

UIPickerView Class Reference
UIDatePicker Class Reference

Iniziamo analizzando il più semplice tra i due, l’ UIDatePicker (che non necessita di delegate) trasciniamone uno su una view oppure inserendo questo codice per generarlo a runtime:

UIDatePicker *datePicker;
datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 150, 0, 0)];
[self.view addSubview:datePicker];

da notare che non importano le dimensioni del frame, il picker ha dimensione fissa.
Vediamo quali sono le più comuni proprietà e metodi che questo oggetto ci mette a disposizione:

maximumDate & minimumDate:

@property(nonatomic, retain) NSDate *maximumDate
@property(nonatomic, retain) NSDate *minimumDate

permettono di limitare il range di variabilità della data impostando la data massima e la data minima selezionabile. Di default vengono impostate entrambe a nil quindi l’utente può selezionare una data arbitrariamente passata o futura.

esempio: (questo esempio è complicato dall’utilizzo della classe nsdate che vedremo un’altra volta.)

NSString *min = @"20042010";
NSString *max = @"22042010";
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"ddMMyyyy"];
NSDate *datemin = [dateFormat dateFromString:min];
NSDate *datemax = [dateFormat dateFromString:max];
[self.view addSubview:datePicker];
datePicker.maximumDate = datemax;
datePicker.minimumDate = datemin;

minuteInterval:

@property(nonatomic) NSInteger minuteInterval

Indica l’intervallo di selezione dei minuti, di default viene posto a 1 ma possiamo modificarlo, purché ci limitiamo ad inserire divisori di 60 (per esempio 2, 5, 30 ma non 23 oppure 45)

datePicker.minuteInterval = 30;

setDate:animated:

questo metodo permette di impostare una data nell’ UIDatePicker a runtime, se animated è impostato a YES verrà visualizzata l’animazione delle rotelle che girano.

datePickerMode:

@property(nonatomic) UIDatePickerMode datePickerMode</strong>

Questa proprietà determina l’aspetto delll’UIDatePicker, se permette la selezione di una data, di un orario, di entrambi o un conto alla rovescia. Il valore di default è UIDatePickerModeDateAndTime.

Gli altri possibili valori sono:

UIDatePickerModeTime
UIDatePickerModeDate
UIDatePickerModeDateAndTime
UIDatePickerModeCountDownTimer

UIDatePickerModeTime

UIDatePickerModeDate

UIDatePickerModeDateAndTime

...ModeCountDownTimer

Veniamo ora al secondo argomento di questa guida, parliamo di UIPickerView.

Proviamo come poc’anzi a creare un pickerview e visualizzarlo nella nostra applicazione:

UIPickerView *Picker;
Picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 150, 0, 0)];
[self.view addSubview:Picker];
UIPickerView *Picker;Picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 150, 0, 0)];
[self.view addSubview:Picker];

Purtroppo il codice sembra non funzionare, il picker non si vede ed al suo posto otteniamo soltato un rettangolo nero, come mai? Ci viene in aiuto la class reference che dice:

“A UIPickerView object requires the cooperation of a delegate for constructing its components and a data source for providing the numbers of components and rows.

Che per chi non mastica l’inglese vuol dire:

“Un oggetto UIPickerView richiede la cooperazione di un degate per costruire i suoi componenti e di un data source che proveda a fornire il numero dei componenti e delle righe.”

Quindi poichè al nostro pickerview non abbiamo specificato nè delegatedatasource, non è in grado di visualizzare nulla, ecco quindi spiegato il rettangolo nero.

Concettualmente delegate e dataprovider potrebbero essere due classi separate e create appositamente per tale scopo, ma spesso viene dato il compito di assolvere a questi ruoli allo stesso File’s Owner dell’uipickerview. Per fare questo quindi scriviamo:

[Picker setDelegate:self];
[Picker setDataSource:self];

Se provassimo adesso ad eseguire il codice vedremmo crashare inesorabilmente la nostra applicazione, ma anche a questo c’è una spiegazione… abbiamo detto al pickerview di interpellare il suo File’s Owner (self) per ricevere tutte le informazioni necessarie per la sua visualizzazione, ma non abbiamo detto al File’s Owner cosa rispondere, quindi in questo empasse l’applicazione va in crash.

Diamo quindi un’occhiata alla reference apple per UIPickerViewDelegate (qui)

scopriamo che la classe che vuol fare da delegare ad un uipickerview deve implementare almeno uno tra questi due metodi:

– pickerView:titleForRow:forComponent:
– pickerView:viewForRow:forComponent:reusingView:

Il secondo è meno utilizzato perché si usa per visualizzare immagini all’interno del picker piuttosto che una descrizione testuale;

Aggiungiamo quindi alla nostra classe questo metodo:

- (NSString *)pickerView:(UIPickerView *)pickerView
			 titleForRow:(NSInteger)row
			forComponent:(NSInteger)component
{
	return [NSString stringWithFormat:@"VALORE NUM:%d",row];
}

non abbiamo ancora terminato, abbiamo implementato il delegate, resta da implementare il datasource.

Leggiamo quindi sempre dalla reference apple (qui) che i metodi da implementare sono tutti e due, e sono:

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component

Il primo specifica quante “rotelle” devono essere disegnate nel picker, mentre il secondo specifica, per ogni “rotella” quanti devono essere i valori presenti. Nel nostro caso possiamo quindi aggiungere:

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
	return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
	return 20;
}

eseguiamo quindi il nostro codice e godiamoci finalmente il nostro UIpickerView!


PickerView


La trattazione di questi oggetti è stata particolarmente lunga e non è affatto esaustiva, invito per tanto tutti a leggere le reference apple per riuscire a sfruttare al massimo questi oggetti.

Un ultimo consiglio per gli amanti di interface builder, potete trascinare i picker come trascinereste qualsiasi altro oggetto, ricordatevi però di impostare nella finestra “connection” il corretto delegate e datasource (ctrl e trascina)