Domanda

Sto scrivendo un piccolo iOS app che interroga un webservice REST XML. Il quadro di rete in uso è AFNetworking .

Situazione

Per interrogare il webservice I sottoclasse AFHTTPClient:

@interface MyApiClient : AFHTTPClient

e nell'attuazione faccio che disponibile come Singleton:

+ (MyApiClient *)sharedClient {
    static MySharedClient *_sharedClient = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedClient = [[self alloc] initWithBaseUrl:[NSUrl URLWithString:@"http://url.to.the.webservice"]];
    });

    return self;
} 

e in initWithBaseURL dico AFNetworking aspettarsi contenuto XML:

[self registerHTTPOperationClass:[AFXMLRequestOperation class]];

Ora posso chiamare getPatch sul singleton dal mio ViewController e nel blocco di successo Inizia il parsing di XML restituito la mia. In NSXMLParserDelegate metodi nella ViewController posso quindi prendere le parti del XML Sono interessato a fare cose e con esso.

Problema

Io voglio avere metodi nella mia HTTPClient Singleton che maniglia tutto ciò che riguarda i modelli di dati webservice e ritorno o elenco dei modelli, invece di XML.

Per esempio io voglio fare qualcosa di simile:

ServerModel *status = [[MyApiClient sharedClient] getServerStatus];

L'ApiClient sarebbe quindi chiamare internamente il webservice, analizzare il codice XML e restituire il modello. Come posso fare ciò? Normalmente avrei usato un delegato che viene chiamata una volta l'XML viene analizzato, ma a causa della natura del Singleton ApiClient ci potrebbero essere più delegati?

La speranza che qualcuno possa fare luce su questo, grazie!

È stato utile?

Soluzione

(Ci scusiamo in anticipo per questo "tipo-di" risposta, ma stiamo lavorando per una soluzione migliore ...)

È necessario fare un passo indietro e pensare a vostro disegno con attenzione.

Stai avendo problemi perché hai un'idea che qualcosa nelle vostre esigenze di progettazione per essere un Singleton, ma in entrambi:

1) che non è effettivamente necessario,

2) qualcosa potrebbe essere già esistente che fa quel lavoro per voi (ad esempio HTTP lib si sta utilizzando),

o

3) Stai facendo la cosa sbagliata un Singleton, o non si è porzionato il vostro disegno nelle parti appropriate di lavorare bene con l'idea Singleton

Quindi, mi puoi dire in modo esplicito il motivo per cui si sta andando per un approccio Singleton? E 'solo per garantire che solo una richiesta di rete può succedere in una volta? C'è qualche nozione di statefulness nel vostro oggetto Singleton? Poi io aggiornare questa risposta o un commento, ecc.

( Digressione: Vorrei anche aggiungere che in alcuni casi ci potrebbe essere una vera e propria necessità di un ' forte ' Singleton - e con questo intendo che ci sia davvero una sola istanza possibile e che il meccanismo è cotto direttamente nel tuo oggetto, come si sta facendo - ma questo non è che l'alternativa è un ' debole ' Singleton, con cui intendo l'oggetto principale. che in realtà il lavoro ha un metodo init normale come al solito, ma l'accesso condiviso a un oggetto comune va via un altro oggetto, che è una sorta di semplice 'fabbrica' che istanzia / tiene l'istanza condivisa. il vantaggio di questa debole idea singoletto è che il codice è più riutilizzabile in contesti diversi - ad esempio, si potrebbe decidere di fare richieste multiple HTTP / sessioni contemporaneamente in un secondo momento - e rende a volte la scrittura di test meno problematici)

.

Altri suggerimenti

Utilizzare i blocchi invece di delegati.

Dalla mia classe ApiClient:

- (void)getPath:(NSString *)path 
     parameters:(NSDictionary *)parameters 
        success:(void (^)(id response))success 
        failure:(void (^)(NSError *error))failure 
{   
    NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters];
    [self enqueueHTTPOperationWithRequest:request success:success failure:failure];
}

-(void)fetchAllUsersSuccess:(void (^)(id))success 
                     failure:(void (^)(NSError *))failure
{
    [self getPath:@"/api/mobile/user/" 
       parameters:nil 
          success:^(id response) {  

                      if([response isKindOfClass:[NSXMLParser class]]){
                          //parse here to new dict
                          success(newDict);
                      } else
                          success(response);

          } failure:^(NSError *error) {
              failure(error);
          }];
}

Ora posso utilizzarlo come:

ServiceApiClient *apiClient = [ServiceApiClient sharedClient];

[apiClient fetchAllUsersSuccess:^(id dict) {
    for (NSDictionary *object in [dict objectForKey:@"objects"]) {
        [ServiceUser addUserFromDictionary:object
                                 inContext:self.managedObjectContext];
    }
    NSError *error= nil;
    [self.managedObjectContext save:&error];
    if (error) {
        NSLog(@"%@", error);
    }
} failure:^(NSError * error) {
    NSLog(@"%@", error);
}];
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top