Commit 47d38ce3 by Dima Bart

Refactor operation classes and add polling support.

parent 5f9ad9b7
......@@ -28,7 +28,10 @@
@interface BUYOperation : NSOperation
- (void)locked:(dispatch_block_t)lockedBlock;
- (void)startExecution;
- (void)finishExecution;
- (void)cancelExecution;
@end
......@@ -70,6 +70,13 @@ typedef NS_ENUM(NSUInteger, BUYOperationState) {
#pragma mark - Setters -
- (void)locked:(dispatch_block_t)lockedBlock
{
[self.lock lock];
lockedBlock();
[self.lock unlock];
}
- (void)setState:(BUYOperationState)state
{
[self.lock lock];
......@@ -102,6 +109,12 @@ typedef NS_ENUM(NSUInteger, BUYOperationState) {
[self startExecution];
}
- (void)cancel
{
[super cancel];
[self cancelExecution];
}
#pragma mark - Execution -
- (void)startExecution
{
......@@ -113,6 +126,11 @@ typedef NS_ENUM(NSUInteger, BUYOperationState) {
self.state = BUYOperationStateFinished;
}
- (void)cancelExecution
{
[self finishExecution];
}
#pragma mark - State -
static inline NSString * BUYOperationStateKeyPath(BUYOperationState state)
......
......@@ -30,11 +30,13 @@ NS_ASSUME_NONNULL_BEGIN
@protocol BUYSerializable;
typedef void (^BUYRequestOperationCompletion)(NSDictionary * _Nullable json, NSURLResponse * _Nullable response, NSError * _Nullable error);
typedef BOOL (^BUYRequestOperationPollingHandler)(NSDictionary * _Nullable json, NSURLResponse * _Nullable response, NSError * _Nullable error);
@interface BUYRequestOperation : BUYOperation
@property (strong, nonatomic, readonly, nonnull) NSURLSession *session;
@property (strong, nonatomic, readonly, nonnull) NSURLRequest *originalRequest;
@property (strong, nonatomic, readonly, nullable) BUYRequestOperationPollingHandler pollingHandler;
+ (instancetype)operationWithSession:(NSURLSession *)session request:(NSURLRequest *)request payload:(id<BUYSerializable> _Nullable)payload completion:(BUYRequestOperationCompletion)completion;
......
......@@ -29,6 +29,8 @@
NSString * const kShopifyError = @"shopify";
typedef void (^BUYRequestJSONCompletion)(NSDictionary *json, NSHTTPURLResponse *response, NSError *error);
#pragma mark - NSURLResponse -
@interface NSHTTPURLResponse (Conveniece)
......@@ -56,6 +58,7 @@ NSString * const kShopifyError = @"shopify";
@interface BUYRequestOperation ()
@property (strong, nonatomic) BUYRequestOperationCompletion completion;
@property (strong, nonatomic) NSURLSessionDataTask *runningTask;
@end
......@@ -91,46 +94,91 @@ NSString * const kShopifyError = @"shopify";
self.completion(nil, response, error);
}
- (void)finishByCancellation
{
[self finishExecution];
}
#pragma mark - Start -
- (void)startExecution
{
if (self.isCancelled) {
[self finishByCancellation];
return;
}
[super startExecution];
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:self.originalRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSURLRequest *request = self.originalRequest;
NSURLSessionDataTask *task = [self requestUsingPollingIfNeeded:request completion:^(NSDictionary *json, NSHTTPURLResponse *response, NSError *error) {
if (response.successful) {
[self finishWithJSON:json response:response];
} else {
[self finishWithError:error response:response];
}
}];
[self locked:^{
self.runningTask = task;
}];
[task resume];
}
- (void)cancelExecution
{
[super cancelExecution];
__block NSURLSessionDataTask *task = nil;
[self locked:^{
task = self.runningTask;
}];
[task cancel];
}
#pragma mark - Requests -
- (NSURLSessionDataTask *)requestUsingPollingIfNeeded:(NSURLRequest *)request completion:(BUYRequestJSONCompletion)completion
{
if (self.isCancelled) {
return nil;
}
return [self request:request completion:^(NSDictionary *json, NSHTTPURLResponse *response, NSError *error) {
if (self.isCancelled) {
[self finishByCancellation];
return;
}
/* ---------------------------------
* If a polling handler is provided
* and it returns YES for continue
* polling, we recursively continue
* the polling process.
*/
if (self.pollingHandler && self.pollingHandler(json, response, error)) {
NSURLSessionDataTask *task = [self requestUsingPollingIfNeeded:request completion:completion];
[self locked:^{
self.runningTask = task;
}];
[task resume];
} else {
completion(json, response, error);
}
}];
}
- (NSURLSessionDataTask *)request:(NSURLRequest *)request completion:(BUYRequestJSONCompletion)completion
{
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:self.originalRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary *json = nil;
if (data.length > 2) { // 2 is the minimum amount of data {} for a JSON Object. Just ignore anything less.
json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
}
NSHTTPURLResponse *httpResponse = (id)response;
if (httpResponse.successful) {
[self finishWithJSON:json response:httpResponse];
} else {
if (!error) {
error = [[NSError alloc] initWithDomain:kShopifyError code:httpResponse.statusCode userInfo:json];
}
[self finishWithError:error response:httpResponse];
if (!httpResponse.successful && !error) {
error = [[NSError alloc] initWithDomain:kShopifyError code:httpResponse.statusCode userInfo:json];
}
completion(json, httpResponse, error);
}];
[task resume];
return task;
}
@end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment