I am using AFNetworking with the singleton model suggested in their example.
+ (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;
}
Initialization is done with a baseURL taken from the user defaults.
My problem is that the baseURL property is read-only. If the user goes to settings and changes the baseURL user default, how can I change it in my client?
Another similar case I have with a need to change the baseURL is an API which requires multiple calls and logic to determine to the right baseURL. And the base url can still change while the app is running (e.g. user changes networking environment requiring a change from local connection to 3G connection via external proxy server.).
I see why the baseURL property is read-only: there are things like networkReachabilityStatus that run in the background and are tied to that setting. This said, it seems fairly easy to have a setBaseURL method that stops monitoring, changes the value, then starts monitoring again...
I guess my design is not right, should I give-up the singleton in this case and re-create the client each time the baseURL should change?
The class AFHTTPClient
is designed to work with a single base URL. This is why it is readonly.
Here are some solutions if you have more than one base URL:
in your AFHTTPClient
subclass override the property qualifier. Place this inside the @interface: @property (readwrite, nonatomic, retain) NSURL *baseURL;
Don't use AFHTTPClient
at all
Create multiple instances of AFHTTPClient
When you create HTTP operations you can override the baseURL. Just set the full URL in the path instead of a relative path.
Hope this helps you.
@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