Skip to content

Commit

Permalink
Handle task completion through dedicated task delegates
Browse files Browse the repository at this point in the history
  • Loading branch information
sebreh committed Apr 12, 2015
1 parent 43ddb36 commit 5517a0e
Show file tree
Hide file tree
Showing 9 changed files with 596 additions and 124 deletions.
12 changes: 6 additions & 6 deletions Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ DEPENDENCIES:
- OHHTTPStubs

SPEC CHECKSUMS:
DDCometClient: 6fc6115df9b5cd4d7481dd20fba53ed5f1feb8d6
Expecta: 03aabd0a89d8dea843baecb19a7fd7466a69a31d
FXReachability: 228b601247952766994ab610b0a83b6c30c64559
OCMock: f6cb8c162ab9d5620dddf411282c7b2c0ee78854
OHHTTPStubs: 6781373b69e0a67b27239799f11764d0fbefac55
DDCometClient: d0c81b6bf58c74b29114440b94ef7027f450f055
Expecta: a354d4633409dd9fe8c4f5ff5130426adbe31628
FXReachability: fc1ea418e5db48cc3e0dd7748f7baf80b144f50f
OCMock: a73f69963a8a542b0b343e2617650e4dca0cbbc2
OHHTTPStubs: b671969016b4c6f5ee3c26080c81114ba82e0710

COCOAPODS: 0.35.0
COCOAPODS: 0.36.0
14 changes: 14 additions & 0 deletions PodioKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,10 @@
50FB3D6A18EB42250021DB48 /* PKTItemsAPI.m in Sources */ = {isa = PBXBuildFile; fileRef = 50FB3D6418EA0DDE0021DB48 /* PKTItemsAPI.m */; };
50FB3D6D18EB57D40021DB48 /* PKTItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 50FB3D6C18EB57D40021DB48 /* PKTItemTests.m */; };
50FB3D6E18EB58560021DB48 /* PKTItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 50FB3D6018EA0CDD0021DB48 /* PKTItem.m */; };
50FC5EC31AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 50FC5EC11AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.h */; };
50FC5EC41AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 50FC5EC21AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.m */; };
50FC5EC51AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 50FC5EC21AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.m */; };
50FC5ECA1AD7EADE00ED3AF3 /* PKTURLSessionTaskDelegateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 50FC5EC91AD7EADE00ED3AF3 /* PKTURLSessionTaskDelegateTests.m */; };
C9FAD0909FD16D61B423947B /* NSNumberFormatter+PKTAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FADC6A54E0D20D7943D795 /* NSNumberFormatter+PKTAdditions.m */; };
C9FAD0BB1D368F8E9CEB9568 /* PKTAppFieldConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FADCA90121ED753BEBC4B3 /* PKTAppFieldConfig.m */; };
C9FAD0CF42F999F167D06571 /* PKTDurationItemFieldValue.m in Sources */ = {isa = PBXBuildFile; fileRef = C9FAD6CC141ECE483EABAB4F /* PKTDurationItemFieldValue.m */; };
Expand Down Expand Up @@ -774,6 +778,9 @@
50FB3D6418EA0DDE0021DB48 /* PKTItemsAPI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKTItemsAPI.m; sourceTree = "<group>"; };
50FB3D6818EB189B0021DB48 /* PKTItemAPITests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKTItemAPITests.m; sourceTree = "<group>"; };
50FB3D6C18EB57D40021DB48 /* PKTItemTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKTItemTests.m; sourceTree = "<group>"; };
50FC5EC11AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PKTURLSessionTaskDelegate.h; sourceTree = "<group>"; };
50FC5EC21AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKTURLSessionTaskDelegate.m; sourceTree = "<group>"; };
50FC5EC91AD7EADE00ED3AF3 /* PKTURLSessionTaskDelegateTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PKTURLSessionTaskDelegateTests.m; sourceTree = "<group>"; };
51B9ED0A10BBDBDB17E0A5E7 /* Pods-podiokittests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-podiokittests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-podiokittests/Pods-podiokittests.debug.xcconfig"; sourceTree = "<group>"; };
662E9ED2E9A9DD7E247969CA /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
749AC896ECA24D14812290D5 /* libPods-podiokittests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-podiokittests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1394,6 +1401,8 @@
506D925D19ED6C8400A7BCB4 /* PKTDatastore.m */,
50E44CDC19FA23C000FB4CE2 /* PKTSecurity.h */,
50E44CDD19FA23C000FB4CE2 /* PKTSecurity.m */,
50FC5EC11AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.h */,
50FC5EC21AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.m */,
);
path = Core;
sourceTree = "<group>";
Expand Down Expand Up @@ -1439,6 +1448,7 @@
505113E5196FE8FA00370285 /* PKTMultipartFormDataTests.m */,
505324B919883E0000700135 /* PKTAsyncTaskTests.m */,
503A3F9D19F5093D0053FFA6 /* PKTDatastoreTests.m */,
50FC5EC91AD7EADE00ED3AF3 /* PKTURLSessionTaskDelegateTests.m */,
);
name = Core;
sourceTree = "<group>";
Expand Down Expand Up @@ -1722,6 +1732,7 @@
5024C5C719616DC400AE28D7 /* PKTUser.h in Headers */,
C9FADA7AD84BE0D81ADEFEC6 /* PKTCategoryOption.h in Headers */,
E47A281D1ABB407A00E6F0FD /* PKTNotificationGroup.h in Headers */,
50FC5EC31AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.h in Headers */,
C9FADEC73A88FBD20E632A4F /* PKTAppFieldConfig.h in Headers */,
502AAB3319FF795B006A0352 /* PKTPushCredential.h in Headers */,
C9FAD5520897CD3F437A17E1 /* PKTItemFieldValue.h in Headers */,
Expand Down Expand Up @@ -2011,6 +2022,7 @@
50DAD43B196404BD00529DB5 /* PKTForm.m in Sources */,
50FB3D6218EA0CDD0021DB48 /* PKTItem.m in Sources */,
50D776301A06E19F00CE26B1 /* PKTConversation.m in Sources */,
50FC5EC41AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.m in Sources */,
5024C5C819616DC400AE28D7 /* PKTUser.m in Sources */,
50395A0419137762004C298C /* NSDateFormatter+PKTAdditions.m in Sources */,
5082425218FC82C1009A1580 /* PKTBlockValueTransformer.m in Sources */,
Expand Down Expand Up @@ -2074,6 +2086,7 @@
50395A0519137762004C298C /* NSDateFormatter+PKTAdditions.m in Sources */,
503959FA191369D4004C298C /* PKTFileAPITests.m in Sources */,
50B49F1C18EE095500B7EDF5 /* PKTAppTests.m in Sources */,
50FC5ECA1AD7EADE00ED3AF3 /* PKTURLSessionTaskDelegateTests.m in Sources */,
50FB3D6D18EB57D40021DB48 /* PKTItemTests.m in Sources */,
5006B082191C245F006FF388 /* PKTCalendarEvent.m in Sources */,
50E068041920A47700552CCF /* PKTOrganizationAPITests.m in Sources */,
Expand Down Expand Up @@ -2194,6 +2207,7 @@
50B49F1618EE092100B7EDF5 /* PKTAppsAPI.m in Sources */,
5032B0B6188EB6DC0080046B /* PKTRequestTests.m in Sources */,
E4BABDCF1897FBD900E9149A /* PKTOAuth2TokenTests.m in Sources */,
50FC5EC51AD7EA8D00ED3AF3 /* PKTURLSessionTaskDelegate.m in Sources */,
50FA507B190112AC009542B9 /* PKTHTTPStubber.m in Sources */,
E4BABDCD1897FA8600E9149A /* PKTOAuth2Token.m in Sources */,
5082427A18FD76D7009A1580 /* NSValueTransformer+PKTTransformers.m in Sources */,
Expand Down
66 changes: 10 additions & 56 deletions PodioKit/Common/Core/PKTClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ typedef NS_ENUM(NSUInteger, PKTClientAuthRequestPolicy) {
PKTClientAuthRequestPolicyIgnore,
};

typedef void (^PKTRequestProgressBlock) (float progress);

/**
* A pending task represents a request that has been requested to be performed but not yet started.
* It might be started immediately or enqueued until the token has been successfully refreshed if expired.
Expand All @@ -45,22 +43,17 @@ @implementation PKTPendingRequest {
dispatch_once_t _cancelledOnceToken;
}

- (instancetype)initWithRequest:(PKTRequest *)request completion:(PKTRequestCompletionBlock)completion {
- (instancetype)initWithRequest:(PKTRequest *)request progress:(PKTRequestProgressBlock)progress completion:(PKTRequestCompletionBlock)completion {
self = [super init];
if (!self) return nil;

_request = request;
_completionBlock = [completion copy];

[self observeProgress];
_progressBlock = [progress copy];

return self;
}

- (void)dealloc {
[self removeProgressObservation];
}

/**
* Starts the pending task by requesting an NSURLSessionTask from the HTTP client and then
* resuming it.
Expand All @@ -69,7 +62,7 @@ - (void)dealloc {
*/
- (void)startWithHTTPClient:(PKTHTTPClient *)client {
dispatch_once(&_startedOnceToken, ^{
self.task = [client taskForRequest:self.request completion:self.completionBlock];
self.task = [client taskForRequest:self.request progress:self.progressBlock completion:self.completionBlock];
self.completionBlock = nil;

[self.task resume];
Expand All @@ -85,52 +78,14 @@ - (void)startWithHTTPClient:(PKTHTTPClient *)client {
- (void)cancelWithHTTPClient:(PKTHTTPClient *)client {
dispatch_once(&_cancelledOnceToken, ^{
if (!self.task) {
self.task = [client taskForRequest:self.request completion:self.completionBlock];
self.task = [client taskForRequest:self.request progress:self.progressBlock completion:self.completionBlock];
self.completionBlock = nil;
}

[self.task cancel];
});
}

- (void)notifyProgress {
if (!self.progressBlock) return;

int64_t expectedBytes = 0;
int64_t completedBytes = 0;

if ([self.task isKindOfClass:[NSURLSessionUploadTask class]]) {
expectedBytes = self.task.countOfBytesExpectedToSend;
completedBytes = self.task.countOfBytesSent;
} else {
expectedBytes = self.task.countOfBytesExpectedToReceive;
completedBytes = self.task.countOfBytesReceived;
}

float progress = 0.f;
if (expectedBytes > 0) {
progress = (double)completedBytes / (double)expectedBytes;
}

self.progressBlock(progress);
}

- (void)observeProgress {
[self addObserver:self forKeyPath:@"task.countOfBytesSent" options:NSKeyValueObservingOptionNew context:NULL];
[self addObserver:self forKeyPath:@"task.countOfBytesReceived" options:NSKeyValueObservingOptionNew context:NULL];
}

- (void)removeProgressObservation {
[self removeObserver:self forKeyPath:@"task.countOfBytesSent"];
[self removeObserver:self forKeyPath:@"task.countOfBytesReceived"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (object == self) {
[self notifyProgress];
}
}

@end

@interface PKTClient ()
Expand Down Expand Up @@ -416,8 +371,13 @@ - (PKTAsyncTask *)enqueueTaskWithRequest:(PKTRequest *)request {

- (PKTPendingRequest *)pendingRequestForRequest:(PKTRequest *)request taskResolver:(PKTAsyncTaskResolver *)taskResolver {
PKT_WEAK_SELF weakSelf = self;
PKT_WEAK(taskResolver) weakResolver = taskResolver;

PKTPendingRequest *pendingRequest = [[PKTPendingRequest alloc] initWithRequest:request completion:^(PKTResponse *response, NSError *error) {
PKTPendingRequest *pendingRequest = [[PKTPendingRequest alloc] initWithRequest:request progress:^(float progress, int64_t totalBytesExpected, int64_t totalBytesReceived) {
// The task made progress
[weakResolver notifyProgress:progress];
} completion:^(PKTResponse *response, NSError *error) {
// The task completed
PKT_STRONG(weakSelf) strongSelf = weakSelf;

if (!error) {
Expand All @@ -432,12 +392,6 @@ - (PKTPendingRequest *)pendingRequestForRequest:(PKTRequest *)request taskResolv
}
}];

PKT_WEAK(taskResolver) weakResolver = taskResolver;

pendingRequest.progressBlock = ^(float progress) {
[weakResolver notifyProgress:progress];
};

return pendingRequest;
}

Expand Down
12 changes: 11 additions & 1 deletion PodioKit/Common/Core/PKTHTTPClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@
*/
typedef void(^PKTRequestCompletionBlock)(PKTResponse *response, NSError *error);

/**
* A progress block to be called whenever a task makes progress.
*
* @param progress The current progress of the task.
* @param totalBytesExpected The total expected number of bytes to be received.
* @param totalBytesReceived The current number of bytes received at the time of calling this block.
*/
typedef void(^PKTRequestProgressBlock)(float progress, int64_t totalBytesExpected, int64_t totalBytesReceived);

@interface PKTHTTPClient : NSObject

/**
Expand Down Expand Up @@ -51,10 +60,11 @@ typedef void(^PKTRequestCompletionBlock)(PKTResponse *response, NSError *error);
* will be executed upon completion.
*
* @param request The request
* @param completion A block to be called when the task makes progress, or nil.
* @param completion A completion handler to be executed on task completion.
*
* @return An NSURLSessionTask
*/
- (NSURLSessionTask *)taskForRequest:(PKTRequest *)request completion:(PKTRequestCompletionBlock)completion;
- (NSURLSessionTask *)taskForRequest:(PKTRequest *)request progress:(PKTRequestProgressBlock)progress completion:(PKTRequestCompletionBlock)completion;

@end
Loading

0 comments on commit 5517a0e

Please sign in to comment.