Frage

Ich schreibe eine kleine iOS -App, die einen XML -Rest -Webservice abfragt. Das verwendete Networking -Framework ist AFNetworking.

Lage

Um den Webservice I abfragen zu können, afhttpclient:

@interface MyApiClient : AFHTTPClient

Und in der Implementierung mache ich das als Singleton zur Verfügung:

+ (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;
} 

und in initWithbaseUrl sage ich AFNetworking, dass er XML -Inhalte erwartet:

[self registerHTTPOperationClass:[AFXMLRequestOperation class]];

Jetzt kann ich Getpatch auf dem Singleton von meinem ViewController anrufen und im Erfolgsblock beginnen meine zurückgegebene XML. In NSXMLParSerDelegate -Methoden im ViewController kann ich dann die Teile der XML auswählen, an denen ich interessiert bin, und damit Dinge damit zu tun.

Problem

Ich möchte Methoden in meinem httpclient Singleton haben, die alles im Zusammenhang mit dem Webservice und der Rückgabe von Datenmodellen oder der Liste von Modellen anstelle von XML verarbeiten.

Zum Beispiel möchte ich so etwas tun:

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

Der Apiclient würde dann den Webservice intern aufrufen, das XML analysieren und das Modell zurückgeben. Wie kann ich das machen? Normalerweise würde ich einen Delegierten verwenden, der aufgerufen wird, sobald der XML analysiert ist, aber aufgrund der Singleton -Natur des Apiclient könnte es mehrere Delegierte geben?

Ich hoffe, jemand kann das Licht darüber werfen, danke!

War es hilfreich?

Lösung

(Entschuldigung im Voraus für diese "Art von" Antwort, aber wir arbeiten auf eine bessere Lösung ...)

Sie müssen einen Schritt zurücktreten und sorgfältig über Ihr Design nachdenken.

Sie haben Probleme, weil Sie eine Idee haben, dass etwas in Ihrem Design ein Singleton sein muss, aber beide:

1) Das ist eigentlich nicht notwendig,

2) Möglicherweise gibt es bereits etwas, das diesen Job für Sie erledigt (z. B. die HTTP -Lib, die Sie verwenden).

oder

3) Sie machen das Falsche zu einem Singleton, oder Sie haben Ihr Design nicht in die entsprechenden Teile ausgelöst, um gut mit der Singleton -Idee zu arbeiten

Können Sie mir also explizit sagen, warum Sie einen Singleton -Ansatz wählen? Soll es nur sicherstellen, dass nur eine Netzwerkanforderung gleichzeitig stattfinden kann? Gibt es in Ihrem Singleton -Objekt einen Begriff der Staatsfestigkeit? Dann aktualisiere ich diese Antwort oder diesen Kommentar usw.

(Abschweifung: Ich würde auch hinzufügen, dass es in einigen Fällen möglicherweise ein echtes Bedürfnis nach einem 'bestehen.stark'Singleton - womit ich meine, dass es wirklich nur eine mögliche Instanz gibt und dass der Mechanismus wie Sie direkt in Ihr Objekt eingebrannt ist -, aber das ist es nicht. Die Alternative ist eine 'schwach'Singleton, womit ich dein Kernobjekt meine, das die Arbeit tatsächlich leistet init Methode wie üblich, aber gemeinsamer Zugriff auf ein gemeinsames Objekt wird über ein anderes Objekt erfolgt, was eine Art einfacher "Fabrik" ist, die die gemeinsam genutzte Instanz instanziiert/hält. Der Vorteil dieser schwachen Singleton -Idee ist, dass Ihr Code in verschiedenen Kontexten wiederverwendbarer ist - z. B. können Sie sich zu einem späteren Zeitpunkt entscheiden, mehrere HTTP -Anforderungen/-sitzungen gleichzeitig durchzuführen - und es macht manchmal weniger problematisch.

Andere Tipps

Verwenden Sie Blöcke anstelle von Delegierten.

Aus meiner apiclient -Klasse:

- (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);
          }];
}

Jetzt kann ich es verwenden wie:

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);
}];
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top