web-dev-qa-db-fra.com

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 de demande d'une grande application que je développe. J'utilise actuellement ASIHTTPRequest pour réellement faire des demandes, mais comme j'ai besoin de nombreux types de demandes différents en raison de nombreuses actions différentes prises dans différents contrôleurs de vue, j'essaie de trouver le meilleur système d'organisation de ces demandes.

Je suis en train de créer des "demandeurs" singleton qui sont conservés par le délégué de l'application et assis à écouter les 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 réponse. Cela résout la plupart de mes problèmes, mais ne gère pas avec élégance les demandes ayant échoué ou les demandes simultanées adressées au même demandeur singleton.

N'importe qui a du succès à concevoir une architecture claire, OO pour faire de nombreux types de demandes dans une application iOS?

50
kevboh

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

  • J'ai un seul objet qui s'occupe de la connectivité réseau, appelons-le un "gestionnaire de réseau". Généralement, cet objet est un singleton (créé à l'aide de macro Cocoa singleton de Matt Gallagher ).
  • Puisque vous utilisez ASIHTTPRequest (ce que je fais toujours, une merveilleuse API), j'ajoute un ivar ASINetworkQueue à l'intérieur de 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 demande réseau dont mon application a besoin (généralement, pour chaque backend REST interaction ou SOAP endpoint). Cela présente un autre avantage (voir ci-dessous pour plus de détails :)
  • Chaque fois qu'un de mes contrôleurs requiert des données (actualisation, 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.). Cela se fait par la file d'attente, ce qui est cool (au 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 de réseau est appelé (rappelez-vous, le gestionnaire de réseau est le délégué de la file d'attente).
  • Le gestionnaire de réseau ne sait pas quoi faire du résultat de chaque demande; par conséquent, il appelle simplement une méthode sur la demande ! N'oubliez pas que les demandes sont des sous-classes de ASIHTTPRequest, vous pouvez donc simplement mettre le code qui gère le résultat de la demande (généralement, 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.). Mettre le code dans chaque sous-classe de demande distincte, en utilisant une méthode polymorphe avec un nom commun à travers les classes de demande, facilite le débogage et la gestion à mon humble avis.
  • Enfin, j'informe les contrôleurs ci-dessus des événements intéressants à l'aide de notifications; l'utilisation d'un protocole 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, puis les notifications sont plus flexibles (vous pouvez avoir plusieurs contrôleurs répondant à la même notification, etc.).

Quoi qu'il en soit, c'est ainsi que je le fais depuis un certain temps, et franchement, cela fonctionne plutôt bien. Je peux étendre le système horizontalement, en ajoutant plus de sous-classes ASIHTTPRequest selon mes besoins, et le cœur du gestionnaire de réseau reste intact.

J'espère que ça aide!

69
Adrian Kosmaczewski

Voici comment je le fais 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 un NSOperationQueue qui accepte AFHTTPRequestOperations (ou AFJSONRequestOperations) car j'utilise généralement AFNetworking pour faire des demandes. Pour ceux-ci, il existe une propriété d'achèvementBlock et failureBlock qui est exécutée en cas de succès ou d'échec de la demande. Sur mon objet singleton, j'aurais une méthode pour lancer une requête réseau particulière, et comme paramètres de cette méthode, j'inclurais un bloc de réussite et d'échec qui peut être passé dans les blocs définis dans la méthode. De cette façon, l'application entière peut effectuer une demande réseau et la portée de l'application à ce stade est disponible pour le singleton dans le bloc qui est transmis à 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 tous les paramètres dont vous avez besoin.

1
Jacob

Essayez STNetTaskQueue , ce qui peut rendre votre demande réutilisable et maintenable.

0
Kevin

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

0
ohho