Comment effectuer des fonctions de rappel dans Objective-C?
Je voudrais juste voir quelques exemples complets et je devrais le comprendre.
Normalement, les rappels dans Objective C sont effectués avec des délégués. Voici un exemple d'implémentation de délégué personnalisé.
En tête de fichier:
@interface MyClass : NSObject {
id delegate;
}
- (void)setDelegate:(id)delegate;
- (void)doSomething;
@end
@interface NSObject(MyDelegateMethods)
- (void)myClassWillDoSomething:(MyClass *)myClass;
- (void)myClassDidDoSomething:(MyClass *)myClass;
@end
Fichier d'implémentation (.m)
@implementation MyClass
- (void)setDelegate:(id)aDelegate {
delegate = aDelegate; /// Not retained
}
- (void)doSomething {
[delegate myClassWillDoSomething:self];
/* DO SOMETHING */
[delegate myClassDidDoSomething:self];
}
@end
Cela illustre l'approche générale. Vous créez une catégorie sur NSObject qui déclare les noms de vos méthodes de rappel. NSObject n'implémente pas réellement ces méthodes. Ce type de catégorie s'appelle un protocole informel, vous dites simplement que de nombreux objets peuvent implémenter ces méthodes. Ils sont un moyen de déclarer en avant la signature de type du sélecteur.
Ensuite, vous avez un objet comme délégué de "MyClass" et MyClass appelle les méthodes de délégué du délégué, le cas échéant. Si les rappels de vos délégués sont facultatifs, vous les garderez généralement sur le site de répartition avec quelque chose du type "if ([delegate respondsToSelector: @selector (myClassWillDoSomething :)) {)". Dans mon exemple, le délégué est requis pour implémenter les deux méthodes.
Au lieu d'un protocole informel, vous pouvez également utiliser un protocole formel défini avec @protocol. Si vous faites cela, vous modifierez le type du setter délégué, et la variable d'instance pour être "id <MyClassDelegate>
"au lieu de" id
".
En outre, vous remarquerez que le délégué n'est pas retenu. Cela est généralement effectué car l'objet qui "possède" les instances de "MyClass" est généralement également le délégué. Si MyClass conservait son délégué, il y aurait un cycle de conservation. C'est une bonne idée dans la méthode dealloc d'une classe qui a une instance MyClass et qui est son délégué pour effacer cette référence de délégué, car c'est un pointeur arrière faible. Sinon, si quelque chose garde l'instance MyClass en vie, vous aurez un pointeur en suspens.
Pour être complet, puisque StackOverflow RSS a juste ressuscité la question de manière aléatoire, l’autre option (la plus récente) consiste à utiliser des blocs:
@interface MyClass: NSObject
{
void (^_completionHandler)(int someParameter);
}
- (void) doSomethingWithCompletionHandler:(void(^)(int))handler;
@end
@implementation MyClass
- (void) doSomethingWithCompletionHandler:(void(^)(int))handler
{
// NOTE: copying is very important if you'll call the callback asynchronously,
// even with garbage collection!
_completionHandler = [handler copy];
// Do stuff, possibly asynchronously...
int result = 5 + 3;
// Call completion handler.
_completionHandler(result);
// Clean up.
[_completionHandler release];
_completionHandler = nil;
}
@end
...
MyClass *foo = [[MyClass alloc] init];
int x = 2;
[foo doSomethingWithCompletionHandler:^(int result){
// Prints 10
NSLog(@"%i", x + result);
}];
Voici un exemple qui garde les concepts de délégués à l’écart et fait simplement un rappel brut.
@interface Foo : NSObject {
}
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector;
@end
@interface Bar : NSObject {
}
@end
@implementation Foo
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector {
/* do lots of stuff */
[object performSelector:selector withObject:self];
}
@end
@implementation Bar
- (void)aMethod {
Foo *foo = [[[Foo alloc] init] autorelease];
[foo doSomethingAndNotifyObject:self withSelector:@selector(fooIsDone:)];
}
- (void)fooIsDone:(id)sender {
NSLog(@"Foo Is Done!");
}
@end
Typiquement, la méthode - [Foo doSomethingAndNotifyObject: withSelector:] serait asynchrone, ce qui rendrait le rappel plus utile qu’il ne l’est ici.
Pour garder cette question à jour, l'introduction de ARC par iOS 5.0 signifie que cela peut être réalisé à l'aide de Blocs Encore plus de manière concise:
@interface Robot: NSObject
+ (void)sayHi:(void(^)(NSString *))callback;
@end
@implementation Robot
+ (void)sayHi:(void(^)(NSString *))callback {
// Return a message to the callback
callback(@"Hello to you too!");
}
@end
[Robot sayHi:^(NSString *reply){
NSLog(@"%@", reply);
}];
Il y a toujours F **** ng Block Syntax si vous oubliez jamais la syntaxe Block d'Objective-C.
CallBack: Il existe 4 types de rappel dans Objective C
Type de sélecteur : vous pouvez voir que NSTimer, UIPangesture sont des exemples de rappel de sélecteur. Utilisé pour une exécution très limitée du code.
Type de délégué : Commun et le plus utilisé dans le cadre Apple. UITableViewDelegate, NSNURLConnectionDelegate. Ils sont généralement utilisés pour afficher le téléchargement de nombreux images du serveur de manière asynchrone, etc.
S'il vous plaît laissez-moi si une autre réponse pour cela. Ça me ferait plaisir.