2012-07-24 13 views
15

Sto utilizzando AFNetworking con il modello Singleton suggerito in their example.modifica AFNetworking baseURL

+ (SGStockRoomHTTPClient *)sharedClient 
{ 
    static SGStockRoomHTTPClient *_sharedClient = nil; 
    static dispatch_once_t oncePredicate; 
    dispatch_once(&oncePredicate, ^{ 
     NSString *baseUrlString = [[NSUserDefaults standardUserDefaults] stringForKey:@"server_root_url_preference"]; 
     _sharedClient = [[self alloc] initWithBaseURL:[NSURL URLWithString:baseUrlString]]; 
    }); 

    return _sharedClient; 
} 

- (id)initWithBaseURL:(NSURL *)url { 
    self = [super initWithBaseURL:url]; 
    if (!self) { 
     return nil; 
    } 
    [self registerHTTPOperationClass:[AFJSONRequestOperation class]]; 
    [self setDefaultHeader:@"Accept" value:@"text/html"]; 
return self; 
} 

L'inizializzazione viene eseguita con un valore baseURL preso dalle impostazioni predefinite dell'utente.

Il mio problema è che la proprietà baseURL è di sola lettura. Se l'utente accede alle impostazioni e modifica l'impostazione predefinita dell'utente baseURL, come posso modificarlo nel mio client?

Un altro caso simile che ho bisogno di cambiare baseURL è un'API che richiede più chiamate e logica per determinare il giusto URL di base. E l'URL base può ancora cambiare mentre l'app è in esecuzione (ad esempio, l'utente cambia l'ambiente di rete che richiede una modifica dalla connessione locale alla connessione 3G tramite un server proxy esterno).

Vedo perché la proprietà baseURL è di sola lettura: ci sono cose come networkReachabilityStatus che vengono eseguite in background e sono legate a tale impostazione. Detto questo, sembra abbastanza facile avere un metodo setBaseURL che interrompe il monitoraggio, modifica il valore, quindi avvia di nuovo il monitoraggio ...

Suppongo che il mio progetto non sia corretto, dovrei rinunciare al singleton in questo caso e ricreare il client ogni volta che il database di base dovrebbe cambiare?

+1

Per chiarire, la questione è abbastanza specifico per AFNetworking: come si dovrebbe usare AFHTTPClient con le API che non dispongono di un URL fisso di base, ma qualcosa che l'utente (o la logica del programma) dovrebbe specificare? L'esempio con i valori predefiniti dell'utente è buono, il codice sopra riportato funziona ma l'utente deve chiudere e riavviare l'app per attivare le modifiche. – caiman

+0

Buona domanda! Ho un problema simile Dovrei cambiare server su un server secondario quando il server primario non funziona. E il ritorno quando il primario quando questo è attivo e di nuovo in esecuzione. –

risposta

22

La classe AFHTTPClient è progettata per funzionare con un unico URL di base. Questo è il motivo per cui è di sola lettura.

Ecco alcune soluzioni se si dispone di più di un URL di base:

  • nel vostro AFHTTPClient sottoclasse sovrascrivere il qualificatore proprietà. Posto questo all'interno del @interface: @property (readwrite, nonatomic, retain) NSURL *baseURL;

  • Non usare AFHTTPClient affatto

  • creare più istanze di AFHTTPClient

  • Quando si crea operazioni che è possibile eseguire l'override del baseURL HTTP. Basta impostare l'URL completo nel percorso anziché un percorso relativo.

+4

Grazie per i vostri suggerimenti! Basta ignorare e rendere la proprietà readwrite pericolosa perché la classe tiene traccia della raggiungibilità del servizio a cui fa riferimento baseURL. Ma potrebbe essere sovrascritto con un'attenta disiscrizione del monitoraggio, quindi la riattivazione. Ho finito per allontanarmi dal modello Singleton e tenendo l'oggetto sottoclasse AFHTTPClient nel mio controller principale. Lì posso sovrascriverlo con un nuovo oggetto fresco quando ho bisogno di cambiare il baseURL. Sono d'accordo con te sulle opzioni 2, 3 e 4 ;-) – caiman

+4

Ho trovato @ opzione phix23 3 funziona meglio per me. I single tendono ad essere più dolorosi del loro valore per molto tempo.Creare una nuova istanza di AFHTTPClient ogni volta che ne hai bisogno è più sensato per le mie app in cui ho utilizzato AFNetworking. È abbastanza indolore in questo modo. –

+1

Odio le pepite di saggezza come @ MattLong, perché finiscono sempre per costringermi a rifattorizzare il mio codice per il meglio! (Ma seriamente, grazie, usare l'approccio non-singleton con un URL di base mutevole è assolutamente la strada da percorrere.) –

0

Spero che questo ti aiuti.

@interface EFApiClient : AFHTTPSessionManager 
@property (nonatomic,assign)BOOL isTestEnvironment ; 
+ (instancetype)sharedMClient; 
@end 


@implementation EFApiClient 
+ (instancetype)sharedMClient 
{ 
    if ([EFApiClient sharedClient].isTestEnvironment) { 
     return [EFApiClient sharedTestClient] ; 
    } 
    else{ 
     return [EFApiClient sharedClient]; 
    } 
} 

+ (instancetype)sharedClient 
{ 
    static EFApiClient *_sharedMClient = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     _sharedMClient = [[EFApiClient alloc] initWithBaseURL:[NSURL URLWithString:@"https://xxx.xxx.com"]]; 
     [EFApiClient clientConfigWithManager:_sharedMClient]; 
    }); 
    return _sharedMClient; 
} 
+ (instancetype)sharedTestClient 
{ 
    static EFApiClient *_sharedMClient = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     _sharedMClient = [[EFApiClient alloc] initWithBaseURL:[NSURL URLWithString:@"https://test.xxx.xxx.com"]]; 
     [EFApiClient clientConfigWithManager:_sharedMClient]; 
    }); 
    return _sharedMClient; 
} 

+ (void)clientConfigWithManager:(EFApiClient *)client 
{ 
    AFSecurityPolicy* policy = [[AFSecurityPolicy alloc] init]; 
    [policy setAllowInvalidCertificates:YES]; 
    [policy setValidatesDomainName:NO]; 
    [client setSecurityPolicy:policy]; 
    client.requestSerializer = [AFHTTPRequestSerializer serializer]; 
    client.responseSerializer = [AFHTTPResponseSerializer serializer]; 
    //client.requestSerializer.HTTPMethodsEncodingParametersInURI = [NSSet setWithArray:@[@"POST", @"GET", @"HEAD"]]; 
    client.responseSerializer = [AFJSONResponseSerializer serializer]; 
    client.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/x-javascript",@"application/json", @"text/json", @"text/html", nil]; 
} 
@end 
+0

Una soluzione diretta è la benvenuta, ma assicurati di aggiungere un contesto attorno ad essa in modo che i tuoi colleghi capiscano come risolve il problema – pratibha