Comment écrire des méthodes lambda en Objective-C?
Le concept d'un lambda dans Objective-C est maintenant encapsulé avec l'idée de Blocks qui sont l'équivalent des fonctions de passage par référence. Bien sûr, on avait sans doute cela déjà en C avec l'idée de pointeurs de fonction; les blocs ne sont qu'un moyen de capturer également l'état local (c'est-à-dire qu'il peut s'agir de fermetures). En fait, les blocs peuvent également être utilisés dans d'autres langages C (sur Mac) - il est proposé de les intégrer à la syntaxe C standard.
Voici un exemple de définition d'un lambda pour multiplier deux nombres ensemble:
int (^mult)(int, int) = ^(int a, int b) { return a*b; };
La première partie déclare une variable, de type ^int(int,int)
, puis l'affecte à l'expression lambda (aka bloc) qui renvoie le multiple de ses deux arguments. Vous pouvez ensuite passer ce fn autour, le définir dans d'autres endroits, etc; vous pouvez même l'utiliser dans d'autres fonctions.
Voici un exemple de définition d'une fonction qui, lorsqu'elle est invoquée, renvoie une autre fonction:
multiplyBy = ^(int a) { return ^(int b) { return b*a; }; };
triple = multiplyBy(3);
Notez que vous pouvez mélanger des blocs avec des types d'objets (généralement en utilisant id
comme type d'objet) et que la plupart des nouvelles structures de données d'objet Objective-C ont une sorte d'opération au niveau du bloc. GCD utilise également des blocs afin de transmettre des événements arbitraires; cependant, notez que GCD peut également être utilisé avec des pointeurs de fonction.
OS X 10.6 a introduit des blocs. Voir la réponse d'AlBlue pour des exemples .
Si vous n'utilisez pas Snow Leopard, vous pouvez obtenir quelque chose de proche de la composition des fonctions en utilisant diverses autres fonctionnalités.
Exemple utilisant des pointeurs de fonction C:
void sayHello() {
NSLog(@"Hello!");
}
void doSomethingTwice(void (*something)(void)) {
something();
something();
}
int main(void) {
doSomethingTwice(sayHello);
return 0;
}
Exemple utilisant le modèle de commande:
@protocol Command <NSObject>
- (void) doSomething;
@end
@interface SayHello : NSObject <Command> {
}
@end
@implementation SayHello
- (void) doSomething {
NSLog(@"Hello!");
}
@end
void doSomethingTwice(id<Command> command) {
[command doSomething];
[command doSomething];
}
int main(void) {
SayHello* sayHello = [[SayHello alloc] init];
doSomethingTwice(sayHello);
[sayHello release];
return 0;
}
Exemple d'utilisation d'un sélecteur:
@interface SaySomething : NSObject {
}
- (void) sayHello;
@end
@implementation SaySomething
- (void) sayHello {
NSLog(@"Hello!");
}
@end
void doSomethingTwice(id<NSObject> obj, SEL selector) {
[obj performSelector:selector];
[obj performSelector:selector];
}
int main(void) {
SaySomething* saySomething = [[SaySomething alloc] init];
doSomethingTwice(saySomething, @selector(sayHello));
[saySomething release];
return 0;
}
J'ai entendu André Pang à NSConference parler de la façon dont les blocs allaient être introduits avec la prochaine version d'Objective-C.
Cela devrait permettre une programmation fonctionnelle.
Edit: Depuis la sortie de Snow Leopard, c'est effectivement le cas. Objective-C a maintenant Blocs .