Comment effectuer des fonctions de rappel dans Objective-C?
Je voudrais juste voir quelques exemples complets et je devrais le comprendre.
Comment effectuer des fonctions de rappel dans Objective-C?
Je voudrais juste voir quelques exemples complets et je devrais le comprendre.
Réponses:
Normalement, les rappels dans l'objectif 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 transmettre la déclaration de type du sélecteur.
Ensuite, vous avez un objet être le délégué de «MyClass» et MyClass appelle les méthodes de délégué sur le délégué comme il convient. Si vos rappels de délégué sont facultatifs, vous les garderez généralement sur le site de répartition avec quelque chose comme "if ([delegate respondsToSelector: @selector (myClassWillDoSomething :)) {". Dans mon exemple, le délégué doit 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 changeriez le type du setter de délégué et la variable d'instance en " id <MyClassDelegate>
" au lieu de simplement " id
".
De plus, vous remarquerez que le délégué n'est pas conservé. Cela est généralement effectué car l'objet qui "possède" des instances de "MyClass" est généralement également le délégué. Si MyClass retenait son délégué, alors il y aurait un cycle de rétention. C'est une bonne idée dans la méthode dealloc d'une classe qui a une instance MyClass et est son délégué pour effacer cette référence de délégué car il s'agit d'un pointeur arrière faible. Sinon, si quelque chose maintient l'instance MyClass en vie, vous aurez un pointeur suspendu.
Par souci d'exhaustivité, puisque StackOverflow RSS vient de ressusciter la question de manière aléatoire pour moi, l'autre option (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 évite les concepts de délégués et ne fait qu'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 d' ARC par iOS 5.0 signifie que cela peut être réalisé en utilisant des blocs de manière encore plus 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 jamais vous oubliez la syntaxe Block d'Objective-C.
+ (void)sayHi:(void(^)(NSString *reply))callback;
pas être+ (void)sayHi:(void(^)(NSString *))callback;
- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
(Remarque parameterTypes
non parameters
)
CallBack: Il existe 4 types de callback dans Objective C
Type de sélecteur : Vous pouvez voir NSTimer, UIPangesture sont les 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 nombreuses images à partir 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.