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> {
...
} |
Continua...
Normalmente un evento, che altro non è che un messaggio, viene risolto (impostato ed implementato) nella stessa classe o contesto, della funzione o procedura “chiamante”. Ad esempio se aggiungiamo un bottone UIButton via codice (programmatically), possiamo trovarci all’interno di una nostra classe UIView o in un UIViewController. In entrambi i casi l’operazione di allocazione e inizializzazione del bottone sarà seguita dall’impostazione del target che dovrà ricevere un messaggio quando si “cliccherà” sul bottone, sul tipo:
1 2 3 4 5 6 7 8 9
| UIButton *bottone = [UIButton buttonWithType:UIButtonTypeRoundedRect];
bottone.frame = CGRectMake(10, 180, 300, 30);
[bottone setTitle:@"Press me" forState:UIControlStateNormal];
// decide chi deve ricevere il messaggio UIControlEventTouchUpInside
[bottone addTarget:self action:@selector(onButtonClicked) forControlEvents:UIControlEventTouchUpInside];
// ...
- (void) onButtonClicked {
// ...
} |
La riga 5 del codice mostrato sopra decide chi (l’oggetto) e cosa (il metodo) “chiamare” quando il nostro bottone è stato premuto. Nell’esempio sopra illustrato si nota anche che l’impostazione del messaggio di pressione viene inviato al metodo onButtonClick implementato più sotto, quindi facente parte dello stesso contesto (o classe). La prima considerazione ovvia che possiamo fare, dunque, è che alterando i parametri self e action potremmo inviare il nostro messaggio ad un qualsiasi altro oggetto, posto quindi al difuori del contesto in uso. Ecco un esempio pratico: una classe UIApplicationDelegate crea un UIViewController:
1 2 3 4 5
| //
// myAppDelegate.m
//
splashScreenController = [SplashScreenController alloc];
[window addSubview:splashScreenController.view]; |
Lo SplashScreenController espone un metodo che permette di animare la UIView associata al UIViewController stesso:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| //
// SplashScreenController.m
//
- (void) animateBackgroundDown {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(onAnimationFinished)];
self.view.frame = (CGRect){0,480,320,480};
[UIView commitAnimations];
}
// ...
- (void) onAnimationFinished {
NSLog(@"Animazione terminata");
} |
Il codice sopra mostra un metodo definito all’interno della classe SplashScreenController di tipo UIViewController. Esso non fa altro che animare la UIView animandola verso il basso e, quando l’animazione è terminata, chiamare il metodo (invia un messaggio a se stesso – da qui self) onAnimationFinished definito più sotto, facente parte sempre della classe SplashScreenController. Ne segue che nella nostra myAppDelegate, quando invocheremo il metodo animateBackgroundDown, non saremo informati della fine dell’animazione:
1 2 3 4
| //
// myAppDelegate.m
//
[splashScreenController animateBackgroundDown]; |
Quello che potremmo desiderare, invece, è realizzare una nuova versione di animateBackgroundDown tale da dirgli a chi inviare il messaggio di fine animazione e quale metodo chiamare. In pratica vogliamo fare in modo di poter scrivere nella nostra classe myAppDelegate:
1 2 3 4 5 6 7 8
| //
// myAppDelegate.m
//
[splashScreenController animateBackgroundDown:self selector:@selector(onAnimationFinished)];
// ...
- (void) onAnimationFinished {
NSLog(@"Animazione terminata");
} |
Questa volta il metodo onAnimationFinished non si trova nel UIViewController, bensì in myAppDelegate. Per fare questo è sufficiente modificare il metodo animateBackgroundDown nel UIViewController nel modo seguente:
1 2 3 4 5 6 7 8 9 10 11 12
| //
// SplashScreenController.m
//
- (void) animateBackgroundDown:(id)target selector:(SEL)selector {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.75];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelegate:target];
[UIView setAnimationDidStopSelector:selector];
self.view.frame = (CGRect){0,480,320,480};
[UIView commitAnimations];
} |
Adesso abbiamo un metodo che accetta il “contesto” (target) e il metodo da chiamare (selector). Adesso, quando l’animazione termina, il messaggio AnimationDidStop sarà inviato a myAppDelegate a qualsiasi altro “oggetto” / classe in grado di riceverlo.
Continua...
Ultimi Commenti
Giovambattista Fazioli: @Nik: Sono contento! In bocca al lupo dunque!!
Nik: Lunedì ho l’esame di informatica su java, grazie mi sei stato utilissimo, il libro che ho era poco chiaro...
Marco: Ti ringrazio moltissimo, mi hai illuminato
ho risolto impostando [cc_objc] //OptionViewController.m -...
Giovambattista Fazioli: @Marco: Ti consiglio un approccio credo più corretto. Se hai eseguito il subclass del tab...
luigi: molto chiaro e semplice devo ammettere che anche scrivendo da un pà difficilmente uso delegati creati da...