ABRequestManager is a lightweight and extensible request manager for iOS/OS X. It requires only instance of NSURLRequest (or NSMutableURLRequest). All requests are stored in the queue. Request manager pulls the head request from queue and run it. And so on until queue is empty.
The recommended way to install Request Manager in your project is via CocoaPods. It's very easy. Just add ABRequestManager
pod to your Podfile
#import "NSURLRequest+RequestManager.h"
...
- ...
{
...
NSURLRequest *request = [NSURLRequest requestWithURL:someURL];
[request startWithCompleteBlock:^(NSHTTPURLResponse *response, id data)
{
// do some response routine
...
} failBlock:^(NSError *error)
{
// handle error
...
}];
...
}
Beware of retain cycles when using
self
#import "NSURLRequest+RequestManager.h"
...
- (...
{
...
NSURLRequest *request = [NSURLRequest requestWithURL:someURL];
[request startWithDelegate:self];
...
}
...
- (void)request:(NSURLRequest *)request didReceiveResponse:(id)response
{
// do some response routine
...
}
...
- (void)request:(NSURLRequest *)request didReceiveError:(NSError *)error
{
// handle error
...
}
...
Request delegate isn't retained by request manager. It means that if you don't sure that request completes before delegate deallocated you must cancel request
If received data needs to be parsed asynchronously, use start with parsing block
Here is example of JSON-response parsing
...
NSURLRequest *request = [NSURLRequest requestWithURL:someURL];
[request startWithCompletedBlock:^(NSHTTPURLResponse *response, id result)
{
// do something with parse JSON-object
...
} failedBlock:^(NSError *error)
{
// handle error
...
} parsingBlock:^id(NSData *data)
{
// parse data to JSON object
id response = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:nil];
return response;
}];
And the same with delegate
...
NSURLRequest *request = [NSURLRequest requestWithURL:someURL];
[request startWithDelegate:self
parsingBlock:^id(NSData *data)
{
// parse data to JSON object
id response = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:nil];
return response;
}];
All actions in block will run in background thread! Try to avoid calling objects of main thread. Otherwise you should synchronize calls
Request will be removed from requests queue. Connection will be dropped if it runs
[request cancelRequest];
It's easy to create request with ABRequestFactory
ABRequestFactory *factory = [ABRequestFactory requestFactory];
NSMutableURLRequest *requestGET = [factory createGETRequest:path];
NSMutableURLRequest *requestPOST = [factory createPOSTRequest:path data:data];
NSMutableURLRequest *requestPUT = [factory createPUTRequest:path data:data];
NSMutableURLRequest *requestDELETE = [factory createDELETERequest:path];
NSMutableURLRequest *requestCustom = [factory createRequest:path method:@"custom_method" data:data];
Use
[ABRequestFactory sharedInstance]
if you don't want instantiate it every time
Create requests with custom options: base host path, request timeout interval, should handle cookies, cache policy, HTTP headers
ABRequestFactory *factory = [ABRequestFactory requestFactory];
factory.options.basePath = @"https://api.my-service.com/";
factory.options.timeout = 30.f;
factory.cookies = NO;
factory.cache = NSURLRequestReturnCacheDataDontLoad;
factory.headers = @{@"Content-Type", @"application/json"};
NSMutableURLRequest *request = [factory createGETRequest:@"news"]
Default
ABRequestFactory
options are same as defaultNSURLRequest
options
Here are some advanced features of ABRequestManager
Every request in Request Manager wrapped into ABRequestWrapper
. Sometimes it's better to use wrapper instead of raw request.
ABRequestWrapper *wrapper = [[ABRequestWrapper alloc] initWithURLRequest:request];
// set completed and failed blocks
[wrapper setCompletedBlock:^(ABRequestWrapper *wrapper, id result)
{
// do some completion actions
...
} failedBlock:^(ABRequestWrapper *wrapper)
{
// show error
...
}];
// set parsing block
[wrapper setParsingBlock:^id(ABRequestWrapper *wrapper)
{
id result = nil;
// do parsing
...
return result;
}];
You aren't limited to only one sharedInstance
. You can use custom instance of ABRequestManager
. But in that case, you should use ABRequestWrapper
instead of NSMutableURLRequest
ABRequestManager *manager = [[ABRequestManager alloc] init];
ABRequestWrapper *wrapper = [[ABRequestWrapper alloc] initWithURLRequest:request];
[wrapper setCompletedBlock:^(ABRequestWrapper *wrapper, id result)
{
MyModel *model = [[MyModel alloc] initWithData:wrapper.data];
[self updateViewWithModel:model];
} failedBlock:^(ABRequestWrapper *wrapper)
{
[UIAlertView showError:wrapper.error.localizedDescription];
}];
[manager addRequestWrapper:wrapper];
Here is good example of complex task with easy solution. Imagine. Application deal with API that requires access via token. When token is expired it returns HTTP-code 401. And if application received this code, it should send 'get access token' request. And then retry last request.
ABRequestWrapper *wrapper = [[ABRequestWrapper alloc] initWithURLRequest:request];
[wrapper setCompletedBlock:^(ABRequestWrapper *wrapper, id result)
{
if (wrapper.response.statusCode == 200)
{
// everything is OK, do something with result
...
}
else if (wrapper.response.statusCode == 401)
{
// send 'get access token'
ABRequestWrapper *getTokenWrapper= [self getAccessTokenRequestWrapper];
[[ABRequestManager sharedInstance] addRequestWrapperFirst:getTokenWrapper];
// retry current requeset
[[ABRequestManager sharedInstance] addRequestWrapper:wrapper];
}
else
{
// handle other status codes
...
}
} failedBlock:^(ABRequestWrapper *wrapper)
{
[UIAlertView showError:wrapper.error.localizedDescription];
}];
First of all you can set host which reachability should be checked.
...
{
...
[[ABRequestManager sharedInstance] setReachabilityCheckHost:@"https://api.myhost.com"];
...
}
...
Default reachability check host is "www.google.com"
Sometimes it can be useful to restart unfinished request when internet connection become available. But when host unreachable, request will be removed from queue. To avoid this you can restart request by implementing optional method of ABRequestDelegate
- (void)requestWrapperDidBecomeUnreachable:(ABRequestWrapper *)wrapper
{
// restarting request
[[ABRequestManager sharedInstance] addRequestWrapperFirst:wrapper];
}
If you don't implement this method delegate will receive
requestWrapper:didFail:
on internet connection lost
Stay tuned with Request Manager updates on @okolodev