Commit 47d38ce3 by Dima Bart

Refactor operation classes and add polling support.

parent 5f9ad9b7
...@@ -28,7 +28,10 @@ ...@@ -28,7 +28,10 @@
@interface BUYOperation : NSOperation @interface BUYOperation : NSOperation
- (void)locked:(dispatch_block_t)lockedBlock;
- (void)startExecution; - (void)startExecution;
- (void)finishExecution; - (void)finishExecution;
- (void)cancelExecution;
@end @end
...@@ -70,6 +70,13 @@ typedef NS_ENUM(NSUInteger, BUYOperationState) { ...@@ -70,6 +70,13 @@ typedef NS_ENUM(NSUInteger, BUYOperationState) {
#pragma mark - Setters - #pragma mark - Setters -
- (void)locked:(dispatch_block_t)lockedBlock
{
[self.lock lock];
lockedBlock();
[self.lock unlock];
}
- (void)setState:(BUYOperationState)state - (void)setState:(BUYOperationState)state
{ {
[self.lock lock]; [self.lock lock];
...@@ -102,6 +109,12 @@ typedef NS_ENUM(NSUInteger, BUYOperationState) { ...@@ -102,6 +109,12 @@ typedef NS_ENUM(NSUInteger, BUYOperationState) {
[self startExecution]; [self startExecution];
} }
- (void)cancel
{
[super cancel];
[self cancelExecution];
}
#pragma mark - Execution - #pragma mark - Execution -
- (void)startExecution - (void)startExecution
{ {
...@@ -113,6 +126,11 @@ typedef NS_ENUM(NSUInteger, BUYOperationState) { ...@@ -113,6 +126,11 @@ typedef NS_ENUM(NSUInteger, BUYOperationState) {
self.state = BUYOperationStateFinished; self.state = BUYOperationStateFinished;
} }
- (void)cancelExecution
{
[self finishExecution];
}
#pragma mark - State - #pragma mark - State -
static inline NSString * BUYOperationStateKeyPath(BUYOperationState state) static inline NSString * BUYOperationStateKeyPath(BUYOperationState state)
......
...@@ -30,11 +30,13 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -30,11 +30,13 @@ NS_ASSUME_NONNULL_BEGIN
@protocol BUYSerializable; @protocol BUYSerializable;
typedef void (^BUYRequestOperationCompletion)(NSDictionary * _Nullable json, NSURLResponse * _Nullable response, NSError * _Nullable error); 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 @interface BUYRequestOperation : BUYOperation
@property (strong, nonatomic, readonly, nonnull) NSURLSession *session; @property (strong, nonatomic, readonly, nonnull) NSURLSession *session;
@property (strong, nonatomic, readonly, nonnull) NSURLRequest *originalRequest; @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; + (instancetype)operationWithSession:(NSURLSession *)session request:(NSURLRequest *)request payload:(id<BUYSerializable> _Nullable)payload completion:(BUYRequestOperationCompletion)completion;
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
NSString * const kShopifyError = @"shopify"; NSString * const kShopifyError = @"shopify";
typedef void (^BUYRequestJSONCompletion)(NSDictionary *json, NSHTTPURLResponse *response, NSError *error);
#pragma mark - NSURLResponse - #pragma mark - NSURLResponse -
@interface NSHTTPURLResponse (Conveniece) @interface NSHTTPURLResponse (Conveniece)
...@@ -56,6 +58,7 @@ NSString * const kShopifyError = @"shopify"; ...@@ -56,6 +58,7 @@ NSString * const kShopifyError = @"shopify";
@interface BUYRequestOperation () @interface BUYRequestOperation ()
@property (strong, nonatomic) BUYRequestOperationCompletion completion; @property (strong, nonatomic) BUYRequestOperationCompletion completion;
@property (strong, nonatomic) NSURLSessionDataTask *runningTask;
@end @end
...@@ -91,46 +94,91 @@ NSString * const kShopifyError = @"shopify"; ...@@ -91,46 +94,91 @@ NSString * const kShopifyError = @"shopify";
self.completion(nil, response, error); self.completion(nil, response, error);
} }
- (void)finishByCancellation
{
[self finishExecution];
}
#pragma mark - Start - #pragma mark - Start -
- (void)startExecution - (void)startExecution
{ {
if (self.isCancelled) { if (self.isCancelled) {
[self finishByCancellation];
return; return;
} }
[super startExecution]; [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) { if (self.isCancelled) {
[self finishByCancellation];
return; 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; NSDictionary *json = nil;
if (data.length > 2) { // 2 is the minimum amount of data {} for a JSON Object. Just ignore anything less. 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]; json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
} }
NSHTTPURLResponse *httpResponse = (id)response; NSHTTPURLResponse *httpResponse = (id)response;
if (httpResponse.successful) { if (!httpResponse.successful && !error) {
[self finishWithJSON:json response:httpResponse]; error = [[NSError alloc] initWithDomain:kShopifyError code:httpResponse.statusCode userInfo:json];
} else {
if (!error) {
error = [[NSError alloc] initWithDomain:kShopifyError code:httpResponse.statusCode userInfo:json];
}
[self finishWithError:error response:httpResponse];
} }
completion(json, httpResponse, error);
}]; }];
return task;
[task resume];
} }
@end @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