Comment implémenter correctement une class Services dans mon application iOS?

Mon scratch principal actuel: implémenter une class de model spécifiquement pour les appels de service à mon application rails.

Voici le scénario:

  • J'ai une class nommée Service qui est une sous-class de NSObject.
  • Le file d'implémentation a quelques methods définies … Regardons doSignUp .
  • J'utilise AFNetworking pour communiquer avec l'API.
  • Depuis mon SignUpViewController , je crée une instance de ma class Service et appelle doSignUp
  • La méthode fonctionne, comme prévu et je reçois la réponse appropriée du server.

Maintenant vient la partie que je ne comprends pas complètement:

  • AFNetworking utilise des blocs pour ses appels de service.
  • À l'intérieur du bloc de succès , j'appelle une méthode d'assistance appelée handleSignUp (également dans la class Service ). Cette méthode parsing essentiellement le JSON et crée un nouvel user (sous-class NSObject). La méthode handSignUp returnne ensuite l'object User .

À ce stade, j'ai un nouvel object Utilisateur et j'ai besoin de renvoyer cet object à mon SignUpViewController … Comment puis-je faire cela?

  • Dois-je essayer d'append cet object à AppDelegate et y accéder à partir de SignUpViewController ? Cette solution pourrait fonctionner pour accéder à diverses propriétés globales mais quand le SignUpViewController saura-t-il quand y accéder?
  • Devrais-je essayer d'append une reference à SignUpViewController dans la class Service ? Cela semble contre-productif … Je pourrais aussi bien append la méthode doSignUp et handSignUp à la SignUpViewController . Il me semble que ma class Service ne devrait pas être au courant d'autres viewControllers.

Voir ci-dessous pour mes exemples de code:

Service.h

//Service.h #import <UIKit/UIKit.h> #import "AFNetworking.h" @interface Services : NSObject - (void) doSignUp:(NSMutableDictionary*)params; @end 

Service.m

 // Service.m #import "Services.h" #import "Config.h" @implementation Services - (void) doSignUp:(NSMutableDictionary*)params { NSURL *url = [NSURL URLWithSsortingng:@"http://MYURL.COM"]; AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; NSURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"signup.json" parameters:params]; AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { [self handleSignUp:JSON]; } failure:nil]; [operation start]; } - (User*) handleSignUp:(NSMutableArray*)json { User * user = nil; if ([[json valueForKey:@"success"] isEqualToSsortingng:@"true"]) { // create user here ... } return user; } 

SignUpViewController.h

 #import "Service.h" @interface SignUpViewController : UIViewController { Service * service; } @property (nonatomic, strong) Service * service; 

SignUpViewController.m

 #import "SignUpViewController.h" @interface SignUpViewController () @end @implementation SignUpViewController @synthesize service = __service; - (IBAction) initSignUp:(id)sender { // create params... [self.service doSignUp:params]; } 

Encore une fois, tout ce code fait ce qu'il est supposé faire … J'ai juste besoin de savoir comment tout devrait communiquer. Comment puis-je alerter le SignUpViewController que le handleSignUp a été appelé et qu'un nouvel object Utilisateur est disponible?

Merci pour votre time, Andre

Autant que je puisse voir, vous ne réalisez pas la nature asynchronous de ce process: en effet, comme les opérations réseau ou E / S prennent beaucoup de time, nous avons tendance à préférer l'access asynchronous, l'appelant (View Controller) appelle un message sur le API Web via le service, puis se met en attente d'une réponse. En fait, le traitement du réseau pourrait être fait sur un process différent ou sur le kernel d'un processeur ou d'un processeur.

Maintenant, comment l'appelant peut-il être notifié par le service lorsque l'opération est terminée? Pour cela, nous devons lier les deux objects en utilisant la Délégation: nous créons un protocole (c'est juste une déclaration de messages auxquels un object répondra) et nous l'implémentons dans notre View Controller, de cette façon celui qui l'utilisera connaîtra à coup sûr quels sont les messages disponibles.

Ensuite, nous allons déclarer un délégué de type id dans notre service qui sera appelé une fois que les opérations seront terminées.

C'est presque comme importer votre ViewController.h dans la class de service et donner au service un pointeur vers le controller de vue, mais fait de la bonne façon (sans references circulaires et en respectant les principes SOLID)

Maintenant du code:

 //service.h @protocol RemoteApiProtocol <NSObject> @required -(void) UserLoggingIn; -(void) UserLoggedIn:(User*)user; -(void) UserLoginError:(NSError *)error; @end 

Le protocole fonctionne comme une petite interface, c'est un contrat entre deux classs / objects. Ensuite, dans votre service, vous pouvez déclarer champ et propriété pour le protocole:

 //Service.h #import <UIKit/UIKit.h> #import "AFNetworking.h" @interface Services : NSObject{ __weak id<RemoteApiProtocol> delegate; } @property (nonatomic, assign) id<RemoteApiProtocol> delegate; - (void) doSignUp:(NSMutableDictionary*)params; @end 

À ce stade, vous implémentez le protocole dans votre controller de vue, en intégrant le contrat que vous venez de créer. De cette façon, le server saura que le délégué sera toujours capable de répondre aux messages de protocole.

 //SignUpViewController.h #import "Service.h" @interface SignUpViewController : UIViewController <RemoteApiProtocol> { Service * service; } @property (nonatomic, strong) Service * service; 

Après la mise en œuvre du protocole, vous pouvez affecter votre controller de vue en tant que délégué pour le server, de cette façon le server, après avoir appelé l'API, pourra appeler le délégué avec le résultat de l'appel. Pour ce faire, vous devez implémenter les messages de protocoles qui seront appelés par le service:

 //SignUpViewController.m #import "SignUpViewController.h" @implementation SignUpViewController @synthesize service = __service; - (IBAction) initSignUp:(id)sender { //create the service with params //... //assign self as the delegate self.service.delegate = self; [self.service doSignUp:params]; } #pragma mark - RemoteApiProtocol -(void) UserLoggingIn { //login started, //you can show a spinner or animation here } -(void) UserLoggedIn:(User*)user { //user logged in , do your stuff here } -(void) UserLoginError:(NSError *)error { NSLog(@"error: %@",error); } @end 

Et enfin vous appelez les messages dans votre service, après avoir appelé les API dans le bloc succès et erreur:

 // Service.m #import "Services.h" #import "Config.h" @implementation Services - (void) doSignUp:(NSMutableDictionary*)params { NSURL *url = [NSURL URLWithSsortingng:@"http://MYURL.COM"]; AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; NSURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"signup.json" parameters:params]; AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { [self handleSignUp:JSON]; } failure:nil]; //Signaling the start of the signup operation to the delegate if(self.delegate){ [self.delegate UserLoggingIn]; } [operation start]; } - (User*) handleSignUp:(NSMutableArray*)json { User * user = nil; if ([[json valueForKey:@"success"] isEqualToSsortingng:@"true"]) { // create user here ... //call the delegate (view controller) passing the user if(self.delegate){ [self.delegate UserLoggedIn:user]; } }else{ //error handling if(self.delegate){ //NSError *error = ... //[self.delegate UserLoginError:error]; } } //return user; } @end 

Vous pouvez searchr une Delegation et / ou une Data Source . Vérifiez ma réponse acceptée dans ce message pour un exemple, et reference à Apple Docs sur le sujet.

Objectif C Voir à la communication du controller

J'espère que cela t'aides.

Ajouter des parameters de bloc de callback à doSignUp (devrait probablement être renommé en signUpWithParams:success:failure: , afin que le controller puisse répondre à l'inscription doSignUp ou doSignUp et avoir le context pour chaque cas disponible pour présenter des informations pertinentes à l'user.

La méthode de délégation fonctionnerait certainement. Vous pouvez essentiellement append un délégué à la class Service et définir le délégué égal au controller de vue avant d'appeler doSignup.

Cependant, je l'implémenterais en utilisant des blocs. Ajoutez un paramètre à la méthode doSignUp qui est un bloc d'achèvement, déclaré dans SignUpViewController. Pour un exemple de comment passer des blocs en tant que parameters, vérifiez simplement la source de AFNetworking.