2012-07-24 10 views
15

Używam AFNetworking z modelem singleton sugerowanym w their example.Zmiana bazy AFNetworkingURL

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

Inicjowanie odbywa się z baseURL pobranym z domyślnych ustawień użytkownika.

Mój problem polega na tym, że właściwość baseURL jest tylko do odczytu. Jeśli użytkownik przejdzie do ustawień i zmieni domyślnego użytkownika bazy danych, jak mogę go zmienić w moim kliencie?

Innym podobnym przypadkiem, jaki mam z potrzebą zmiany baseURL, jest interfejs API, który wymaga wielu wywołań i logiki w celu ustalenia właściwego podstawowego adresu e-mail. A adres URL bazy wciąż może się zmieniać, gdy aplikacja jest uruchomiona (np. Użytkownik zmienia środowisko sieciowe, które wymaga zmiany z połączenia lokalnego na połączenie 3G za pośrednictwem zewnętrznego serwera proxy).

Widzę, dlaczego właściwość baseURL jest tylko do odczytu: istnieją rzeczy takie jak networkReachabilityStatus, które działają w tle i są powiązane z tym ustawieniem. To powiedziawszy, wydaje się dość łatwe mieć metodę setBaseURL, która zatrzymuje monitorowanie, zmienia wartość, a następnie rozpoczyna monitorowanie ponownie ...

Myślę, że mój projekt jest nie w porządku, powinienem zrezygnować z singleton w tym przypadku i ponownie utworzyć klienta za każdym razem, gdy zmienią się baseURL?

+1

Aby wyjaśnić, pytanie jest dość specyficzne AFNetworking: w jaki sposób należy stosować AFHTTPClient z API, które nie mają stałego podstawowego adresu URL, ale coś użytkownik (lub program sterujący) należy podać? Przykład z domyślnymi ustawieniami użytkownika jest dobry, powyższy kod działa, ale użytkownik musi zamknąć i ponownie uruchomić aplikację, aby aktywować zmiany. – caiman

+0

Dobre pytanie! Mam podobny problem. Powinienem przełączyć serwer na serwer pomocniczy, gdy serwer główny jest wyłączony. I przełącz się z powrotem, gdy główny, kiedy to działa i działa ponownie. –

Odpowiedz

22

Klasa AFHTTPClient jest przeznaczona do pracy z jednym podstawowym adresem URL. To dlatego jest tylko do odczytu.

Oto niektóre rozwiązania, jeśli masz więcej niż jeden adres URL Base:

  • w AFHTTPClient podklasy zastąpić kwalifikator nieruchomości. Umieść to wewnątrz @interface: @property (readwrite, nonatomic, retain) NSURL *baseURL;

  • Nie używaj AFHTTPClient wcale

  • Tworzenie wielu wystąpień AFHTTPClient

  • Podczas tworzenia operacji można zastąpić baseURL HTTP. Wystarczy ustawić pełny adres URL w ścieżce zamiast ścieżki względnej.

+4

Dzięki za sugestie! Zastępowanie i nadpisywanie właściwości jest niebezpieczne, ponieważ klasa śledzi osiągalność usługi przywoływanej przez baseURL. Ale można go zastąpić ostrożnym anulowaniem monitorowania, a następnie ponownej aktywacji. Zakończyłem odejście od modelu singleton i zatrzymanie obiektu podklasy AFHTTPClient w moim głównym kontrolerze. Tam mogę go zastąpić nowym świeżym obiektem, gdy potrzebuję zmienić baseURL. Zgadzam się z Tobą na opcje 2, 3 i 4 ;-) – caiman

+4

Znalazłem opcję @ phix23, która najlepiej pasuje do mnie. Singletony wydają się być większym bólem niż ich wartość.Właśnie tworzenie nowej instancji klasy AFHTTPClient za każdym razem, gdy jej potrzebujesz, ma największy sens dla moich aplikacji, w których korzystałem z AFNetworking. W ten sposób jest dość bezbolesny. –

+1

Nienawidzę samorodków mądrości, takich jak @ MattLong, ponieważ zawsze kończą się na zmuszaniu mnie do refaktoryzacji mojego kodu na lepsze! (Ale poważnie, dziękuję.) Stosowanie podejścia nie będącego singletonem ze zmieniającym się bazowym adresem URL jest absolutnie drogą do zrobienia.) –

0

Mam nadzieję, że to pomoże.

@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

Bezpośrednie rozwiązanie jest mile widziane, ale upewnij się, że dodałeś do niego kontekst, aby inni użytkownicy zrozumieli, jak rozwiązuje problem – pratibha