Skip to content

Commit

Permalink
Fixing progress block execution logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Yuru Taustahuzau committed Aug 10, 2014
2 parents c29578b + c7633bb commit 2287181
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,9 @@
*/
@property (assign, nonatomic) NSTimeInterval timeoutInterval;

/**
* Any value enabled using downloading progress block.
*/
@property (assign, nonatomic) int progressBlockParameter;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ - (id)init
_postParameter = (int)NSNotFound;
_syncCall = NO;
_timeoutInterval = 60;
_progressBlockParameter = (int)NSNotFound;
}

return self;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,10 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {
[self stop];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)aData {
[self.data appendData:aData];
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.data appendData:data];
RFWSLogVerbose(@"URL connection(%p) to URL: %@ received data: %@", connection, [connection.currentRequest.URL absoluteString], [NSString stringWithUTF8String:[self.data bytes]]);
[self updateDownloadProgress:(float)[data length] / (float)self.expectedContentLenght];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@


#import "RFWebServiceCancellable.h"
#import "RFWebServiceClient.h"


@protocol RFAuthenticating;
Expand All @@ -58,17 +59,26 @@
*/
@property (nonatomic, copy, readonly) NSArray *attributes;
/**
The serialized data from the request.
* The serialized data from the request.
*/
@property (strong, nonatomic) id serializedData;
/**
The response success block.
* The response success block.
*/
@property (copy, nonatomic) void (^successBlock)(id result);
/**
The response failure block.
* The response failure block.
*/
@property (copy, nonatomic) void (^failureBlock)(id error);
/**
* Current progress of downloading data from web server
*/
@property (assign, nonatomic, readonly) float downloadProgress;
/**
*
*/
@property (assign, nonatomic, readonly) long long expectedContentLenght;

/**
Indicates that the request has been cancelled.
*/
Expand All @@ -83,4 +93,6 @@

- (void)cancel;

- (void)updateDownloadProgress:(float)progress;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,18 @@ @interface RFDownloader () {
NSURLConnection * _connection;
RFLooper * _looper;
NSMutableArray * _successCodes;
RFWebServiceClientDownloadProgressBlock _progressBlock;
}

@property (strong, nonatomic) NSError *downloadError;
@property (strong, nonatomic) NSMutableData *data;
@property (strong, nonatomic) NSHTTPURLResponse *response;
@property (assign, nonatomic) long long expectedContentLenght;
@property (strong, nonatomic) RFWebServiceCall * callAttribute;
@property (strong, nonatomic) RFWebServiceCache * cacheAttribute;
@property (strong, nonatomic) NSDictionary * values;
@property (strong, nonatomic) RFWebServiceCall *callAttribute;
@property (strong, nonatomic) RFWebServiceCache *cacheAttribute;
@property (strong, nonatomic) NSDictionary *values;
@property (assign, atomic, readwrite, getter = isRequestCancelled) BOOL requestCancelled;
@property (copy, nonatomic) RFWebServiceClientDownloadProgressBlock progressBlock;
@property (assign, nonatomic) long long expectedContentLenght;

- (void)stop;

Expand Down Expand Up @@ -143,6 +145,9 @@ - (void)checkCacheAndStart {
return;
}

[self prepareDownloadBlock];
[self updateDownloadProgress:0.0];

id<RFWebServiceCachingManaging> cacheManager = [RFServiceProvider webServiceCacheManager];
RFWebResponse *cachedResponse;
if (!self.cacheAttribute.cacheDisabled) {
Expand Down Expand Up @@ -211,6 +216,17 @@ - (void)cacheAndFinishWithResult:(NSData *)result response:(NSHTTPURLResponse *)
[self downloaderFinishedWithResult:result response:response error:error];
}

- (void)stop {
_connection = nil;
if (!self.requestCancelled) { // If request is cancelled already, simply release variables
[self fillErrorUserInfoAndCleanData];
[self cacheAndFinishWithResult:_data response:_response error:_downloadError];
}
[_looper stop];
_looper = nil;

}

- (void)downloaderFinishedWithResult:(NSData *)result response:(NSHTTPURLResponse *)response error:(NSError *)downloaderError {
__block id resultData = result;
__block NSError *resultError = downloaderError;
Expand All @@ -226,6 +242,7 @@ - (void)downloaderFinishedWithResult:(NSData *)result response:(NSHTTPURLRespons
// Perform callback block
self.downloadError = resultError;
if (!self.downloadError) {
[self updateDownloadProgress:1.0];
self.serializedData = resultData;
[self performSelector:@selector(performSuccessBlockOnSpecificThread) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];
}
Expand All @@ -247,23 +264,20 @@ - (void)downloaderFinishedWithResult:(NSData *)result response:(NSHTTPURLRespons
return serializationDelegate;
}

- (void)stop {
_connection = nil;
if (!self.requestCancelled) { // If request is cancelled already, simply release variables
[self fillErrorUserInfoAndCleanData];
[self cacheAndFinishWithResult:_data response:_response error:_downloadError];
}
[_looper stop];
_looper = nil;

- (void)updateDownloadProgress:(float)progress {
_downloadProgress = progress;
[self performSelector:@selector(performProgressBlockOnSpecificThread) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES];
}

- (NSUInteger)receivedData {
return [_data length];
}

- (long long)expectedContentLenght {
return _expectedContentLenght;
- (void)prepareDownloadBlock {
if (_callAttribute.progressBlockParameter != (int)NSNotFound) {
self.progressBlock = self.values[[NSString stringWithFormat:@"%d", _callAttribute.progressBlockParameter]];
NSAssert(self.progressBlock != nil, @"RFWebServiceCall attribute on parameter for progress block is invalid");
}
}

- (NSMutableURLRequest *)requestForUrl:(NSURL * const)anUrl withMethod:(NSString * const)method withBody:(NSData *)httpBody values:(NSDictionary *)values {
Expand Down Expand Up @@ -316,6 +330,12 @@ -(void)performSuccessBlockOnSpecificThread {
[self freeCompletionBlocks];
}

-(void)performProgressBlockOnSpecificThread {
if (self.progressBlock) {
self.progressBlock(_downloadProgress, self.expectedContentLenght);
}
}

-(void)performFailureBlockOnSpecificThread {
if (self.failureBlock) {
self.failureBlock(_downloadError);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ + (void)encodeParameters:(NSArray *)parameterList attributes:(NSArray *)attribut
|| object == [NSNull null]) {
encodedObject = object;
}
else if ([[object class] isSubclassOfClass:NSClassFromString(@"NSBlock")]) {
encodedObject = [object copy];
}
else {
if ([serializator respondsToSelector:@selector(serializeObject:)]) {
encodedObject = [serializator serializeObject:object];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,20 +112,26 @@ - (void)dynamicWebServiceCallWithArguments:(NSMutableArray *)parameterList forIn
successBlock = lastParameter;
}

// if there are parameters, the last one can be the prepareToLoad block
id prepareToLoadBlock = [self lastObjectIfBlock:parameterList];
// if there are parameters, and progress block is not the last one.
// Then the last one can be the prepareToLoad block
NSString *methodName = NSStringFromSelector(invocation.selector);
RFWebServiceCall *callAttribute = [[self class] RF_attributeForMethod:methodName withAttributeType:[RFWebServiceCall class]];

id prepareToLoadBlock;
if (callAttribute.progressBlockParameter != (int)[parameterList count] - 1) {
prepareToLoadBlock = [self lastObjectIfBlock:parameterList];
}

// finally pass the parameters to the dynamic method
id result = [self executeDynamicInstanceMethodForSelector:invocation.selector parameters:parameterList prepareToLoadBlock:prepareToLoadBlock success:successBlock failure:failureBlock];
id result = [self executeDynamicInstanceMethod:methodName parameters:parameterList prepareToLoadBlock:prepareToLoadBlock success:successBlock failure:failureBlock];
[invocation setReturnValue:&result];
}

- (id<RFWebServiceCancellable>)executeDynamicInstanceMethodForSelector:(SEL)selector
- (id<RFWebServiceCancellable>)executeDynamicInstanceMethod:(NSString *)methodName
parameters:(NSArray *)parameterList
prepareToLoadBlock:(RFWebServiceClientPrepareForSendRequestBlock)prepareToLoadBlock
success:(id)successBlock
failure:(id)failureBlock {
NSString *methodName = NSStringFromSelector(selector);
NSArray *attributes = [[self class] RF_attributesForMethod:methodName];

__block RFDownloader *downloader = [[RFDownloader alloc] initWithClient:self attributes:attributes authenticationProvider:self.authenticationProvider];
Expand All @@ -148,7 +154,6 @@ - (void)dynamicWebServiceCallWithArguments:(NSMutableArray *)parameterList forIn
}

- (void)prepareRequestParameterForCallWithAttributes:(NSArray *)attributes parameters:(NSArray *)parameterList downloader:(RFDownloader *)downloader prepareForSendRequestBlock:(RFWebServiceClientPrepareForSendRequestBlock)prepareForSendRequestBlock {

__block NSData *bodyData;
__block NSDictionary *parametersDictionary;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@


typedef void (^RFWebServiceClientPrepareForSendRequestBlock)(NSMutableURLRequest* serviceRequest);
typedef void (^RFWebServiceClientDownloadProgressBlock)(float progress, long long expectedContentLenght);


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,13 @@ RF_ATTRIBUTE(RFMultipartData, boundary = @"sdfsfsf")
RF_ATTRIBUTE(RFWebServiceCall, serializationDisabled = YES, method = @"PUT")
- (id<RFWebServiceCancellable>)testPutBodyPresenceWithData:(NSString *)string success:(void(^)(id result))successBlock failure:(void(^)(NSError *error))failureBlock;

RF_ATTRIBUTE(RFWebServiceCall, serializationDisabled = YES)
- (id<RFWebServiceCancellable>)testDownloadingPrepareBlock:(RFWebServiceClientPrepareForSendRequestBlock)prepareBlock success:(void(^)(NSDictionary *albumsInfo))successBlock failure:(void(^)(NSError *error))failureBlock;

RF_ATTRIBUTE(RFWebServiceCall, serializationDisabled = YES, progressBlockParameter = 0)
- (id<RFWebServiceCancellable>)testDownloadingProgressBlock:(RFWebServiceClientDownloadProgressBlock)progressBlock success:(void(^)(NSDictionary *albumsInfo))successBlock failure:(void(^)(NSError *error))failureBlock;

RF_ATTRIBUTE(RFWebServiceCall, serializationDisabled = YES, progressBlockParameter = 0)
- (id<RFWebServiceCancellable>)testDownloadingWithProgressBlock:(RFWebServiceClientDownloadProgressBlock)progressBlock prepareBlock:(RFWebServiceClientPrepareForSendRequestBlock)prepareBlock success:(void(^)(NSDictionary *albumsInfo))successBlock failure:(void(^)(NSError *error))failureBlock;

@end
83 changes: 83 additions & 0 deletions Framework/ROADWebService/ROADWebserviceTest/RFWebServiceTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -426,4 +426,87 @@ - (void)testPutMethodToHaveBody {
XCTAssertTrue(isSuccess, @"Put methods did not have body.");
}

- (void)testDownloadingPrepareAndProgressBlock {
RFConcreteWebServiceClient *webClient = [[RFConcreteWebServiceClient alloc] initWithServiceRoot:@"http://test.simple.call"];
__block BOOL isPrepareFinished = NO;
__block int prepareBlockCounter = 0;
__block BOOL isProgressFinished = NO;
__block int progressBlockCounter = 0;
__block BOOL isFinished = NO;
[webClient testDownloadingWithProgressBlock:^(float progress, long long expectedContentLenght) {
progressBlockCounter++;
isProgressFinished = YES;
} prepareBlock:^(NSMutableURLRequest *serviceRequest) {
prepareBlockCounter++;
isPrepareFinished = YES;
} success:^(id response) {
isFinished = YES;
} failure:^(NSError *error) {
isFinished = YES;
}];

while (!isPrepareFinished || !isProgressFinished) {
[[NSRunLoop currentRunLoop] runUntilDate:[[NSDate alloc] initWithTimeIntervalSinceNow:0.2]];
}

XCTAssertTrue(isProgressFinished, @"Web service progress block was not executed");
XCTAssertEqual(progressBlockCounter, 2, @"Web service progress block was unexpected number of times");
XCTAssertEqual(prepareBlockCounter, 1, @"Web service prepare block was unexpected number of times");
XCTAssertTrue(isPrepareFinished, @"Web service prepare block was not executed");
}

- (void)testPrepareBlockExecution {
RFConcreteWebServiceClient *webClient = [[RFConcreteWebServiceClient alloc] initWithServiceRoot:@"http://test.simple.call"];
__block BOOL isPrepareFinished = NO;
__block int prepareBlockCounter = 0;
__block BOOL isFinished = NO;
[webClient testDownloadingPrepareBlock:^(NSMutableURLRequest *serviceRequest) {
prepareBlockCounter++;
isPrepareFinished = YES;
} success:^(id response) {
isFinished = YES;
} failure:^(NSError *error) {
isFinished = YES;
}];

while (!isPrepareFinished) {
[[NSRunLoop currentRunLoop] runUntilDate:[[NSDate alloc] initWithTimeIntervalSinceNow:0.2]];
}

XCTAssertEqual(prepareBlockCounter, 1, @"Web service prepare block was unexpected number of times");
XCTAssertTrue(isPrepareFinished, @"Web service prepare block was not executed");
}

- (void)testDownloadingProgressBlock {
RFConcreteWebServiceClient *webClient = [[RFConcreteWebServiceClient alloc] initWithServiceRoot:@"http://test.simple.call"];
__block BOOL isProgressFinished = NO;
__block int progressBlockCounter = 0;
__block BOOL isStartProgressNotified = NO;
__block BOOL isEndProgressNotified = NO;
__block BOOL isFinished = NO;
[webClient testDownloadingProgressBlock:^(float progress, long long expectedContentLenght) {
progressBlockCounter++;
isProgressFinished = YES;
if (progress == 0) {
isStartProgressNotified = YES;
}
if (progress == 1.0) {
isEndProgressNotified = YES;
}
} success:^(id response) {
isFinished = YES;
} failure:^(NSError *error) {
isFinished = YES;
}];

while (!isFinished) {
[[NSRunLoop currentRunLoop] runUntilDate:[[NSDate alloc] initWithTimeIntervalSinceNow:0.2]];
}

XCTAssertTrue(isProgressFinished, @"Web service progress block was not executed");
XCTAssertTrue(isStartProgressNotified, @"Web service progress block notified about start downloading");
XCTAssertTrue(isEndProgressNotified, @"Web service progress block notified about finish downloading");
XCTAssertEqual(progressBlockCounter, 2, @"Web service progress block was unexpected number of times");
}

@end

0 comments on commit 2287181

Please sign in to comment.