web-dev-qa-db-fra.com

Comment effectuer des rappels dans Objective-C

Comment effectuer des fonctions de rappel dans Objective-C?

Je voudrais juste voir quelques exemples complets et je devrais le comprendre.

117
ReachConnection

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.

93
Jon Hess

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);
}];
135
Jens Ayton

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.

49
Jon Hess

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.

8
Ryan Brodie

CallBack: Il existe 4 types de rappel dans Objective C

  1. 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.

  2. 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.

  3. NSNotifications : NotificationCenter est l’une des fonctionnalités de l’objectif C qui notifiait plusieurs destinataires au moment où l’événement se produisait.
  4. Blocs : les blocs sont plus couramment utilisés dans la programmation Objective C. C'est une fonctionnalité très utile utilisée pour exécuter des morceaux de code. Vous pouvez également vous référer au tutoriel pour comprendre: Tutoriel sur les blocs

S'il vous plaît laissez-moi si une autre réponse pour cela. Ça me ferait plaisir.

3
Anil Gupta