Pregunta

Estoy escribiendo una pequeña aplicación iOS que consulte un servicio web XML REST. El marco de redes en uso es Avenida.

Situación

Para consultar el servicio web, subclasié AfhttpClient:

@interface MyApiClient : AFHTTPClient

Y en la implementación lo pongo a disposición de 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;
} 

Y en InitWithBaseurl le digo a AfNetWorking que espere contenido XML:

[self registerHTTPOperationClass:[AFXMLRequestOperation class]];

Ahora puedo llamar a GetPatch en Singleton desde mi ViewController y en el bloque de éxito comenzar a analizar mi XML devuelto. En los métodos NSXMLParSerDelegate en ViewController, puedo elegir las partes del XML que estoy interesado y hacer cosas con él.

Problema

Quiero tener métodos en mi httpclient singleton que manejen todo lo relacionado con el servicio web y devuelva los modelos de datos o la lista de modelos en lugar de XML.

Por ejemplo, quiero hacer algo como esto:

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

El apiclient llamaría internamente el servicio web, analizaría el XML y devolvería el modelo. ¿Cómo puedo hacer eso? Normalmente usaría un delegado que se llama una vez que se analiza el XML, pero debido a la naturaleza singleton del apiclient, ¿podría haber múltiples delegados?

Espero que alguien pueda arrojar luz sobre esto, ¡gracias!

¿Fue útil?

Solución

(Disculpas de antemano por esta respuesta de "tipo de", pero estamos trabajando para una mejor solución ...)

Debe dar un paso atrás y pensar en su diseño cuidadosamente.

Tienes problemas porque tienes una idea de que algo en tu diseño debe ser un singleton, pero tampoco:

1) Eso no es realmente necesario

2) Algo podría existir que haga ese trabajo por usted (por ejemplo, el HTTP LIB que está usando),

o

3) Estás haciendo lo incorrecto un singleton, o no has porciones tu diseño en las partes apropiadas para funcionar bien con la idea de singleton

Entonces, ¿puedes decirme explícitamente por qué vas por un enfoque de singleton? ¿Es solo para garantizar que solo una solicitud de red pueda ocurrir a la vez? ¿Hay alguna noción de estado en su objeto singleton? Luego actualizaré esta respuesta o comentario, etc.

(Digresión: También agregaría que en algunos casos podría haber una verdadera necesidad de un 'fuerte'Singleton, por lo que quiero decir que realmente solo hay una instancia posible, y que el mecanismo se hornea directamente en su objeto, como lo está haciendo, pero esto no es así. La alternativa es una 'débil'singleton, por lo que me refiero a tu objeto central que realmente hace el trabajo tiene una simple init El método como de costumbre, pero el acceso compartido a un objeto común pasa a través de otro objeto, que es una especie de 'fábrica' simple que instancia/contiene la instancia compartida. La ventaja de esta idea débil singleton es que su código es más reutilizable en diferentes contextos, por ejemplo, podría decidir hacer múltiples solicitudes/sesiones HTTP simultáneamente en un momento posterior, y a veces hace que las pruebas de escritura sean menos problemáticas).

Otros consejos

Use bloques en lugar de delegados.

De mi clase 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);
          }];
}

Ahora puedo usarlo como:

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);
}];
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top