Fonction déléguer vs fonction de callback

Je travaille sur une plate-forme iOS, je veux savoir ce qu'est une fonction de délégué et quelle est une fonction de callback? quelle est la différence entre les deux types de fonction ou ils sont les mêmes?

exemple de la fonction de délégué est numberOfRowsInSection dans le protocole UITableViewDelegate et l'exemple de la fonction de callback est didReceiveLocalNotification dans appDelegate.m

Pouvons-nous créer notre propre fonction de callback en Objective-C, si OUI, donner un exemple …

Je vous remercie..

    Quelques pensées:

    1. Vous suggérez que didReceiveLocationNotification était une "fonction de callback", mais il s'agit simplement d'une méthode déléguée du protocole UIApplicationDelegate . Ainsi, numberOfRowsInSection et didReceiveLocalNotification sont simplement des methods déléguées.

      Quelque chose de plus semblable à une fonction de callback générique serait le selector lors de la planification d'un NSTimer ou de la définition du gestionnaire pour un UIGestureRecognizer , où le choix du nom de la méthode n'est pas prédéterminé.

      Ou les callbacks sont largement utilisés dans CFArray .

    2. Mais, la racine de votre question est less sur la terminologie, mais plutôt sur la façon de définir une interface où l'appelant peut spécifier une méthode qu'un autre object appellera (de manière asynchronous) à une date ultérieure. Il y a quelques templates communs:

      • Bloquer le paramètre à la méthode : Il est de plus en plus courant de définir des methods qui prennent un bloc en paramètre. Par exemple, vous pouvez avoir une méthode définie comme suit:

         - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSSsortingng *)filename completion:(void (^)(NSData *results, NSSsortingng *filename))completion { NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ completion(data, filename); }); }]; [task resume]; return task; } 

        Ce troisième paramètre, completion , est un bloc de code qui sera appelé avec le téléchargement terminé. Ainsi, vous pouvez appeler cette méthode comme suit:

         [self downloadAsynchronously:url filename:filename completion:^(NSData *results, NSSsortingng *filename) { NSLog(@"Downloaded %d bytes", [results length]); [results writeToFile:filename atomically:YES]; }]; NSLog(@"%s done", __FUNCTION__); 

        Vous verrez que le message "terminé" apparaît immédiatement et que le bloc d' completion sera appelé lorsque le téléchargement sera terminé. Il faut certes du time pour s'habituer au désordre disgracieux de la ponctuation qui constitue une définition de paramètre / variable de bloc, mais une fois que vous connaissez la syntaxe de bloc, vous apprécierez vraiment ce model. Il élimine la déconnection entre l'invocation de certaines methods et la définition d'une fonction de callback distincte.

        Si vous voulez simplifier la syntaxe de traitement des blocs en tant que parameters, vous pouvez en fait définir un typedef pour votre bloc d'achèvement:

         typedef void (^DownloadCompletionBlock)(NSData *results, NSSsortingng *filename); 

        Et puis la déclaration de méthode, elle-même, est simplifiée:

         - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSSsortingng *)filename completion:(DownloadCompletionBlock)completion { NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ completion(data, filename); }); }]; [task resume]; return task; } 
      • Modèle de protocole délégué : L'autre technique courante de communication entre objects est le model de protocole délégué. D'abord, vous définissez le protocole (la nature de l'interface "callback"):

         @protocol DownloadDelegate <NSObject> - (NSURLSessionTask *)didFinishedDownload:(NSData *)data filename:(NSSsortingng *)filename; @end 

        Ensuite, vous définissez votre class qui appellera cette méthode DownloadDelegate :

         @interface Downloader : NSObject @property (nonatomic, weak) id<DownloadDelegate> delegate; - (instancetype)initWithDelegate:(id<DownloadDelegate>)delegate; - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSSsortingng *)filename; @end @implementation Downloader - (instancetype)initWithDelegate:(id<DownloadDelegate>)delegate { self = [super init]; if (self) { _delegate = delegate; } return self; } - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSSsortingng *)filename { NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ [self.delegate didFinishedDownload:data filename:filename]; }); }]; [task resume]; return task; } @end 

        Et enfin, le controller de vue d'origine qui utilise cette nouvelle class Downloader doit se conformer au protocole DownloadDelegate :

         @interface ViewController () <DownloadDelegate> @end 

        Et définissez la méthode de protocole:

         - (void)didFinishedDownload:(NSData *)data filename:(NSSsortingng *)filename { NSLog(@"Downloaded %d bytes", [data length]); [data writeToFile:filename atomically:YES]; } 

        Et effectuez le téléchargement:

         Downloader *downloader = [[Downloader alloc] initWithDelegate:self]; [downloader downloadAsynchronously:url filename:filename]; NSLog(@"%s done", __FUNCTION__); 
      • Modèle de sélecteur : Un model que vous voyez dans certains objects Cocoa (par exemple NSTimer , UIPanGestureRecognizer ) est la notion de passage d'un sélecteur en tant que paramètre. Par exemple, nous aurions pu définir notre méthode de téléchargement comme suit:

         - (NSURLSessionTask *)downloadAsynchronously:(NSURL *)url filename:(NSSsortingng *)filename target:(id)target selector:(SEL)selector { id __weak weakTarget = target; // so that the dispatch_async won't retain the selector NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [weakTarget performSelector:selector withObject:data withObject:filename]; #pragma clang diagnostic pop }); }]; [task resume]; return task; } 

        Vous invoqueriez alors cela comme suit:

         [self downloadAsynchronously:url filename:filename target:self selector:@selector(didFinishedDownload:filename:)]; 

        Mais vous devez également définir cette méthode séparée qui sera appelée lorsque le téléchargement est terminé:

         - (void)didFinishedDownload:(NSData *)data filename:(NSSsortingng *)filename { NSLog(@"Downloaded %d bytes", [data length]); [data writeToFile:filename atomically:YES]; } 

        Personnellement, je trouve que ce model est trop fragile et dépend des interfaces de coordination sans aucune aide du compilateur. Mais je l'inclue pour un peu de reference historique étant donné que ce model est utilisé dans les classs plus anciennes de Cocoa.

      • Notifications : L'autre mécanisme pour fournir les résultats d'une méthode asynchronous consiste à envoyer une notification locale. Ceci est généralement plus utile lorsque (a) le destinataire potentiel des résultats de la request de réseau est inconnu au moment où la request a été lancée; ou (b) il peut y avoir plusieurs classs qui veulent être informées de cet événement. Ainsi, la request de réseau peut publier une notification d'un nom particulier quand c'est fait, et tout object qui souhaite être informé de cet événement peut s'append en tant qu'observateur pour cette notification locale via le NSNotificationCenter .

        Ce n'est pas un "callback" en soi, mais représente un autre model pour qu'un object soit informé de l'achèvement d'une tâche asynchronous.

    Ce sont quelques exemples de templates de "callback". Clairement, l'exemple fourni était arbitraire et sortingvial, mais j'espère que cela devrait vous donner une idée de vos alternatives. Les deux techniques les plus courantes, de nos jours, sont les blocs et les templates de delegates. Les blocs sont de plus en plus préférés lorsqu'une interface simple et élégante est nécessaire. Mais pour les interfaces riches et compliquées, les delegates sont très communs.