49 votes

Quelle est la meilleure architecture pour une application iOS qui effectue de nombreuses requêtes réseau ?

Je suis en train de repenser mon approche de l'architecture des requêtes d'une grande application que je suis en train de développer. J'utilise actuellement ASIHTTPRequest pour effectuer les requêtes, mais comme j'ai besoin de nombreux types de requêtes différents à la suite de nombreuses actions différentes effectuées dans différents contrôleurs de vue, j'essaie de trouver le meilleur système pour organiser ces requêtes.

Je construis actuellement des "demandeurs" singletons qui sont retenus par le délégué de l'application et restent à l'écoute des NSNotifications qui signalent qu'une demande doit être faite ; ils font la demande, écoutent la réponse et envoient une nouvelle NSNotification avec les données de la réponse. Cela résout la plupart de mes problèmes, mais ne permet pas de gérer de manière élégante les demandes qui échouent ou les demandes simultanées au même demandeur singleton.

Quelqu'un a-t-il réussi à concevoir une architecture OO claire pour effectuer de nombreux types de requêtes différents dans une application iOS ?

69voto

akosma Points 6336

Après avoir essayé plusieurs approches, c'est une architecture qui me donne d'excellents résultats, qui est facile à documenter, à comprendre, à maintenir et à étendre :

  • J'ai un objet unique qui s'occupe de la connectivité du réseau, appelons-le "gestionnaire de réseau". En général, cet objet est un singleton (créé à l'aide de la commande La macro Cocoa singleton de Matt Gallagher ).
  • Puisque vous utilisez ASIHTTPRequest (ce que je fais toujours, merveilleuse API), j'ajoute un ivar ASINetworkQueue dans mon gestionnaire de réseau. Je fais du gestionnaire de réseau le délégué de cette file d'attente.
  • Je crée des sous-classes de ASIHTTPRequest pour chaque type de requête réseau dont mon application a besoin (typiquement, pour chaque interaction REST ou endpoint SOAP). Cela présente un autre avantage (voir ci-dessous pour les détails :)
  • Chaque fois qu'un de mes contrôleurs a besoin de données (rafraîchissement, viewDidAppear, etc.), le gestionnaire de réseau crée une instance de la sous-classe ASIHTTPRequest requise, puis l'ajoute à la file d'attente.
  • L'ASINetworkQueue s'occupe des problèmes de bande passante (selon que vous êtes sur 3G, EDGE ou GPRS ou Wifi, vous avez plus de bande passante, et vous pouvez traiter plus de demandes, etc). Ceci est fait par la file d'attente, ce qui est cool (du moins, c'est l'une des choses que je comprends que cette file d'attente fait, j'espère que je ne me trompe pas :).
  • Chaque fois qu'une demande se termine ou échoue, le gestionnaire du réseau est appelé (rappelez-vous, le gestionnaire du réseau est le délégué de la file d'attente).
  • Le gestionnaire de réseau ne sait pas quoi faire avec le résultat de chaque requête ; il appelle donc simplement une méthode sur la demande ! Rappelez-vous, les requêtes sont des sous-classes de ASIHTTPRequest, donc vous pouvez simplement mettre le code qui gère le résultat de la requête (typiquement, la désérialisation de JSON ou XML en objets réels, le déclenchement d'autres connexions réseau, la mise à jour des magasins Core Data, etc). Le fait de placer le code dans chaque sous-classe de demande distincte, en utilisant une méthode polymorphe avec un nom commun à toutes les classes de demande, rend le débogage et la gestion très faciles, à mon avis.
  • Enfin, j'informe les contrôleurs ci-dessus des événements intéressants en utilisant des notifications ; l'utilisation d'un protocole de délégué n'est pas une bonne idée, car dans votre application, vous avez généralement de nombreux contrôleurs qui parlent à votre gestionnaire de réseau, et les notifications sont plus flexibles (vous pouvez avoir plusieurs contrôleurs qui répondent à la même notification, etc).

Quoi qu'il en soit, c'est ainsi que j'ai procédé pendant un certain temps, et franchement, cela fonctionne plutôt bien. Je peux étendre le système horizontalement, en ajoutant des sous-classes ASIHTTPRequest au fur et à mesure de mes besoins, et le cœur du gestionnaire de réseau reste intact.

J'espère que cela vous aidera !

1voto

Jacob Points 442

Voici comment je procède généralement. Moi aussi, j'ai un objet singleton utilisé pour faire des requêtes réseau. Pour les demandes qui doivent être faites souvent, j'ai une NSOperationQueue qui accepte les AFHTTPRequestOperations (ou AFJSONRequestOperations) puisque j'utilise généralement AFNetworking pour faire des demandes. Pour celles-ci, il existe une propriété completionBlock et failureBlock qui est exécutée en cas de succès ou d'échec de la requête. Sur mon objet singleton, je disposerais d'une méthode pour initier une requête réseau particulière, et comme paramètres à cette méthode, j'inclurais un bloc de réussite et un bloc d'échec qui peuvent être passés dans les blocs définis dans la méthode. De cette façon, l'ensemble de l'application peut faire une demande de réseau, et la portée de l'application à ce moment-là est disponible pour le singleton dans le bloc qui est passé à la méthode. Par exemple...(en utilisant ARC)

        @implementation NetworkManager

    -(void)makeRequestWithSuccess:(void(^)(void))successBlock failure:(void(^)(NSError *error))failureBlock

    {
        NSURL *url = [NSURL URLWithString:@"some URL"];

        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];

        [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
            [responseObject doSomething];

            if (successBlock)
                dispatch_async(dispatch_get_main_queue(), successBlock);

        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

            if (failureBlock)
                dispatch_async(dispatch_get_main_queue(), ^{
                    failureBlock(error);
                });
        }];

        [self.operationQueue addOperation:op];
    }
@end

Et vous pouvez toujours faire en sorte que le bloc de réussite prenne les paramètres que vous voulez faire circuler.

0voto

ohho Points 17243

Le site entièrement chargé Le projet est une bonne lecture.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X