Изменение базы AFNetworkingURL

Я использую AFNetworking с моделью singleton, предложенной в их примере.

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

Инициализация выполняется с помощью baseURL, взятого из пользовательских значений по умолчанию.

Моя проблема в том, что свойство baseURL доступно только для чтения. Если пользователь переходит к настройкам и изменяет пользователя baseURL по умолчанию, как я могу его изменить в моем клиенте?

Другим подобным случаем, с которым мне нужно изменить baseURL, является API, который требует множественных вызовов и логики для определения правильного baseURL. И базовый url все равно может измениться во время работы приложения (например, пользователь меняет сетевую среду, требующую изменения от локального подключения к 3G-соединению через внешний прокси-сервер.)

Я вижу, почему свойство baseURL доступно только для чтения: есть такие вещи, как networkReachabilityStatus, которые работают в фоновом режиме и привязаны к этому параметру. Это говорит о том, что довольно просто иметь метод setBaseURL, который останавливает мониторинг, изменяет значение, а затем снова начинает мониторинг...

Я думаю, что мой дизайн не прав, я должен отказаться от синглтона в этом случае и повторно создать клиента каждый раз, когда baseURL должен измениться?

Ответы

Ответ 1

Класс AFHTTPClient предназначен для работы с одним базовым URL-адресом. Вот почему это только для чтения.

Вот несколько решений, если у вас более одного базового URL:

  • в подклассе AFHTTPClient переопределить квалификатор свойства. Поместите это внутри @interface: @property (readwrite, nonatomic, retain) NSURL *baseURL;

  • Не используйте AFHTTPClient вообще

  • Создайте несколько экземпляров AFHTTPClient

  • При создании операций HTTP вы можете переопределить baseURL. Просто установите полный URL-адрес в пути вместо относительного пути.

Ответ 2

Надеюсь, это поможет вам.

@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