Skip to content

Commit

Permalink
Added a method to track progress using a well defined protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
keithpitt committed Aug 23, 2011
1 parent bd03f2c commit a978b41
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 20 deletions.
31 changes: 31 additions & 0 deletions Classes/DKAPIProgress.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// DKAPIProgress.h
// DKAPIRequest
//
// Created by Keith Pitt on 23/08/11.
// Copyright 2011 Mostly Disco. All rights reserved.
//

#import "DKAPIProgressProtocol.h"

typedef enum {

DKAPIProgressDownload,

DKAPIProgressUpload

} DKAPIProgressMethod;

@interface DKAPIProgress : NSObject

@property (nonatomic, retain) id <DKAPIProgressProtocol> delegate;

@property (nonatomic, retain) DKAPIRequest * apiRequest;

@property (nonatomic) DKAPIProgressMethod progressMethod;

- (id)initWithDelegate:(id <DKAPIProgressProtocol>)progressDelegate progressMethod:(DKAPIProgressMethod)method apiRequest:(DKAPIRequest *)request;

- (void)setProgress:(float)progress;

@end
53 changes: 53 additions & 0 deletions Classes/DKAPIProgress.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// DKAPIProgress.m
// DKAPIRequest
//
// Created by Keith Pitt on 23/08/11.
// Copyright 2011 Mostly Disco. All rights reserved.
//

#import "DKAPIProgress.h"

@implementation DKAPIProgress

@synthesize delegate, progressMethod, apiRequest;

- (id)initWithDelegate:(id <DKAPIProgressProtocol>)progressDelegate progressMethod:(DKAPIProgressMethod)method apiRequest:(DKAPIRequest *)request {

if ((self = [super init])) {
self.delegate = progressDelegate;
self.progressMethod = method;
self.apiRequest = request;
}

return self;

}

- (void)setProgress:(float)progress {

// Forward the progress float to the correct method on the delegate (if it responds
// to the selector)

if (progressMethod == DKAPIProgressUpload && [self.delegate respondsToSelector:@selector(apiRequest:uploadProgress:)]) {

[self.delegate apiRequest:self.apiRequest uploadProgress:progress];

} else if (progressMethod == DKAPIProgressDownload && [self.delegate respondsToSelector:@selector(apiRequest:downloadProgress:)]) {

[self.delegate apiRequest:self.apiRequest downloadProgress:progress];

}

}

- (void)dealloc {

self.delegate = nil;
self.apiRequest = nil;

[super dealloc];

}

@end
18 changes: 18 additions & 0 deletions Classes/DKAPIProgressProtocol.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// DKAPIProgressProtocol.h
// DKAPIRequest
//
// Created by Keith Pitt on 23/08/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//

@class DKAPIRequest;

@protocol DKAPIProgressProtocol <NSObject>

@optional

- (void)apiRequest:(DKAPIRequest *)apiRequest downloadProgress:(float)progress;
- (void)apiRequest:(DKAPIRequest *)apiRequest uploadProgress:(float)progress;

@end
8 changes: 3 additions & 5 deletions Classes/DKAPIRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,11 @@ typedef void (^DKAPIRequestFinishBlock)(DKAPIResponse *, NSError *);

@property (nonatomic, assign) DKAPICacheStrategy cacheStrategy;

@property (nonatomic, retain) id uploadProgressDelegate;
@property (nonatomic, retain) id delegate;

@property (nonatomic, retain) id downloadProgressDelegate;
@property (nonatomic, retain) NSURL * url;

@property (readonly) NSURL * url;

@property (readonly) NSString * requestMethod;
@property (nonatomic, retain) NSString * requestMethod;

@property (readonly) NSDate * requestStartTime;

Expand Down
41 changes: 29 additions & 12 deletions Classes/DKAPIRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,26 @@
#import "DKAPIResponse.h"
#import "DKAPIFormData.h"

#import "DKAPIProgressProtocol.h"
#import "DKAPIProgress.h"

#import "DKAPILogger.h"

@implementation DKAPIRequest

@synthesize finishBlock, parameters, formDataRequest;

@synthesize uploadProgressDelegate, downloadProgressDelegate;

@synthesize cacheStrategy;

@synthesize requestStartTime;
@synthesize url, requestMethod, finishBlock, parameters, formDataRequest, delegate, cacheStrategy, requestStartTime;

- (id)initWithURL:(NSURL *)requestURL requestMethod:(NSString *)method parameters:(NSDictionary *)params {

if ((self = [super init])) {

formDataRequest = [[ASIFormDataRequest alloc] initWithURL:requestURL];

formDataRequest.requestMethod = method;
// Set local properties
self.url = requestURL;
self.requestMethod = requestMethod;

// Create the ASIFormDataRequest
formDataRequest = [[ASIFormDataRequest alloc] initWithURL:self.url];
formDataRequest.requestMethod = self.requestMethod;
formDataRequest.delegate = self;
formDataRequest.timeOutSeconds = 120;
formDataRequest.shouldAttemptPersistentConnection = NO;
Expand Down Expand Up @@ -145,6 +146,23 @@ - (void)startAsynchronous {

} else {

// Setup the progress indicator delegates (if our protocol conforms to the protocol)
if (delegate && [delegate conformsToProtocol:@protocol(DKAPIProgressProtocol)]) {

// Create progress forwarders to wrap the setProgress call to more dynamic protocl as defined in
// the DKAPIProgressProtocol protocol

DKAPIProgress * uploadForwarder = [[DKAPIProgress alloc] initWithDelegate:delegate progressMethod:DKAPIProgressUpload apiRequest:self];
DKAPIProgress * downloadForwarder = [[DKAPIProgress alloc] initWithDelegate:delegate progressMethod:DKAPIProgressDownload apiRequest:self];

formDataRequest.downloadProgressDelegate = downloadForwarder;
formDataRequest.uploadProgressDelegate = uploadForwarder;

[uploadForwarder release];
[downloadForwarder release];

}

// Start the request asynchronously
[formDataRequest startAsynchronous];

Expand Down Expand Up @@ -195,8 +213,7 @@ - (void)dealloc {
[formDataRequest release];
[requestStartTime release];

[uploadProgressDelegate release];
[downloadProgressDelegate release];
[delegate release];

[super dealloc];

Expand Down
48 changes: 45 additions & 3 deletions DKAPIRequest.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
530D4B95140232D200A33292 /* DKAPIFormDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 530D4B94140232D200A33292 /* DKAPIFormDataSpec.m */; };
530D4B97140237EE00A33292 /* OCMock-iPhone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 530D4B96140237EE00A33292 /* OCMock-iPhone.framework */; };
530D4BA314024EA200A33292 /* MockInterceptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 530D4BA214024EA200A33292 /* MockInterceptor.m */; };
53156486140359C8009A79E5 /* DKAPIProgress.m in Sources */ = {isa = PBXBuildFile; fileRef = 53156485140359C8009A79E5 /* DKAPIProgress.m */; };
5315648E14036049009A79E5 /* MockProgressDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5315648D14036049009A79E5 /* MockProgressDelegate.m */; };
53156492140360A9009A79E5 /* DKAPIProgressSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 53156491140360A9009A79E5 /* DKAPIProgressSpec.m */; };
537874B014010A0A00D9B746 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 537874AF14010A0A00D9B746 /* main.m */; };
537874BD14010A1F00D9B746 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 537874BC14010A1F00D9B746 /* UIKit.framework */; };
537874BF14010A2500D9B746 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 537874BE14010A2500D9B746 /* Foundation.framework */; };
Expand Down Expand Up @@ -87,6 +90,12 @@
530D4B96140237EE00A33292 /* OCMock-iPhone.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "OCMock-iPhone.framework"; path = "External/OCMock-iPhone.framework"; sourceTree = "<group>"; };
530D4BA114024EA200A33292 /* MockInterceptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockInterceptor.h; sourceTree = "<group>"; };
530D4BA214024EA200A33292 /* MockInterceptor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MockInterceptor.m; sourceTree = "<group>"; };
53156484140359C8009A79E5 /* DKAPIProgress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DKAPIProgress.h; sourceTree = "<group>"; };
53156485140359C8009A79E5 /* DKAPIProgress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DKAPIProgress.m; sourceTree = "<group>"; };
5315648814035D4C009A79E5 /* DKAPIProgressProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DKAPIProgressProtocol.h; sourceTree = "<group>"; };
5315648C14036049009A79E5 /* MockProgressDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockProgressDelegate.h; sourceTree = "<group>"; };
5315648D14036049009A79E5 /* MockProgressDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MockProgressDelegate.m; sourceTree = "<group>"; };
53156491140360A9009A79E5 /* DKAPIProgressSpec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DKAPIProgressSpec.m; sourceTree = "<group>"; };
5378749F14010A0A00D9B746 /* Specs.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Specs.app; sourceTree = BUILT_PRODUCTS_DIR; };
537874AB14010A0A00D9B746 /* Specs-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Specs-Info.plist"; sourceTree = "<group>"; };
537874AF14010A0A00D9B746 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -217,12 +226,11 @@
530D4B6F14022FF200A33292 /* Classes */ = {
isa = PBXGroup;
children = (
5315648A14035E27009A79E5 /* DKAPIProgress */,
5315648914035E1E009A79E5 /* DKAPIInterceptor */,
530D4B7014022FF200A33292 /* DKAPICacheStrategy.h */,
530D4B7114022FF200A33292 /* DKAPIFormData.h */,
530D4B7214022FF200A33292 /* DKAPIFormData.m */,
530D4B7314022FF200A33292 /* DKAPIInterceptor.h */,
530D4B7414022FF200A33292 /* DKAPIInterceptor.m */,
530D4B7514022FF200A33292 /* DKAPIInterceptorProtocol.h */,
530D4B7614022FF200A33292 /* DKAPILogger.h */,
530D4B7714022FF200A33292 /* DKAPIRequest.h */,
530D4B7814022FF200A33292 /* DKAPIRequest.m */,
Expand All @@ -243,6 +251,35 @@
name = Interceptors;
sourceTree = "<group>";
};
5315648914035E1E009A79E5 /* DKAPIInterceptor */ = {
isa = PBXGroup;
children = (
530D4B7314022FF200A33292 /* DKAPIInterceptor.h */,
530D4B7414022FF200A33292 /* DKAPIInterceptor.m */,
530D4B7514022FF200A33292 /* DKAPIInterceptorProtocol.h */,
);
name = DKAPIInterceptor;
sourceTree = "<group>";
};
5315648A14035E27009A79E5 /* DKAPIProgress */ = {
isa = PBXGroup;
children = (
5315648814035D4C009A79E5 /* DKAPIProgressProtocol.h */,
53156484140359C8009A79E5 /* DKAPIProgress.h */,
53156485140359C8009A79E5 /* DKAPIProgress.m */,
);
name = DKAPIProgress;
sourceTree = "<group>";
};
5315648B14036037009A79E5 /* Delegates */ = {
isa = PBXGroup;
children = (
5315648C14036049009A79E5 /* MockProgressDelegate.h */,
5315648D14036049009A79E5 /* MockProgressDelegate.m */,
);
name = Delegates;
sourceTree = "<group>";
};
5378747D140109AE00D9B746 = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -282,13 +319,15 @@
537874A914010A0A00D9B746 /* Specs */ = {
isa = PBXGroup;
children = (
5315648B14036037009A79E5 /* Delegates */,
530D4BA014024E8400A33292 /* Interceptors */,
537874AA14010A0A00D9B746 /* Support */,
530D4B8B1402327F00A33292 /* DKAPIInterceptorSpec.m */,
530D4B8C1402327F00A33292 /* DKAPIRequestSpec.m */,
530D4B94140232D200A33292 /* DKAPIFormDataSpec.m */,
530D4B8D1402327F00A33292 /* DKAPIResponseSpec.m */,
530D4B8E1402327F00A33292 /* DKAPIStubSpec.m */,
53156491140360A9009A79E5 /* DKAPIProgressSpec.m */,
);
path = Specs;
sourceTree = "<group>";
Expand Down Expand Up @@ -658,6 +697,9 @@
530D4B931402327F00A33292 /* DKAPIStubSpec.m in Sources */,
530D4B95140232D200A33292 /* DKAPIFormDataSpec.m in Sources */,
530D4BA314024EA200A33292 /* MockInterceptor.m in Sources */,
53156486140359C8009A79E5 /* DKAPIProgress.m in Sources */,
5315648E14036049009A79E5 /* MockProgressDelegate.m in Sources */,
53156492140360A9009A79E5 /* DKAPIProgressSpec.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
66 changes: 66 additions & 0 deletions Specs/DKAPIProgressSpec.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// DKAPIProgressSpec.m
// DKAPIRequest
//
// Created by Keith Pitt on 22/08/11.
// Copyright 2011 Mostly Disco. All rights reserved.
//

#import "SpecHelper.h"

#import "DKAPIProgress.h"
#import "DKAPIRequest.h"

#import "MockProgressDelegate.h"

SPEC_BEGIN(DKAPIProgressSpec)

__block DKAPIRequest * request;
__block DKAPIProgress * progresss;
__block id progressDelegate;

beforeEach(^{

request = [DKAPIRequest new];
progressDelegate = [OCMockObject niceMockForClass:[MockProgressDelegate class]];
progresss = [[DKAPIProgress alloc] initWithDelegate:progressDelegate progressMethod:DKAPIProgressUpload apiRequest:request];

});

describe(@"- (id)initWithDelegate:progressMethod:apiRequest:", ^{

it(@"should set the appropriate properties", ^{

expect(progresss.delegate).toEqual(progressDelegate);
expect(progresss.apiRequest).toEqual(request);
expect(progresss.progressMethod).toEqual(DKAPIProgressUpload);

});

});

describe(@"- (void)setProgress:(float)progress;", ^{

it(@"should forward to the upload method correctly", ^{

progresss.progressMethod = DKAPIProgressUpload;

[[progressDelegate expect] apiRequest:request uploadProgress:0.75];

[progresss setProgress:0.75];

});

it(@"should forward to the download method correctly", ^{

progresss.progressMethod = DKAPIProgressDownload;

[[progressDelegate expect] apiRequest:request downloadProgress:0.75];

[progresss setProgress:0.75];

});

});

SPEC_END
13 changes: 13 additions & 0 deletions Specs/MockProgressDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// MockProgressDelegate.h
// DKAPIRequest
//
// Created by Keith Pitt on 23/08/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "DKAPIProgressProtocol.h"

@interface MockProgressDelegate : NSObject <DKAPIProgressProtocol>

@end
Loading

0 comments on commit a978b41

Please sign in to comment.