Ben Copsey

Improve ASINetworkQueue progress tracking behaviour when adding requests to a qu…

…eue that is already running
... ... @@ -26,19 +26,19 @@
id uploadProgressDelegate;
// Total amount uploaded so far for all requests in this queue
unsigned long long uploadProgressBytes;
unsigned long long bytesUploadedSoFar;
// Total amount to be uploaded for all requests in this queue - requests add to this figure as they work out how much data they have to transmit
unsigned long long uploadProgressTotalBytes;
unsigned long long totalBytesToUpload;
// Download progress indicator, probably an NSProgressIndicator or UIProgressView
id downloadProgressDelegate;
// Total amount downloaded so far for all requests in this queue
unsigned long long downloadProgressBytes;
unsigned long long bytesDownloadedSoFar;
// Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers
unsigned long long downloadProgressTotalBytes;
unsigned long long totalBytesToDownload;
// When YES, the queue will cancel all requests when a request fails. Default is YES
BOOL shouldCancelAllRequestsOnFailure;
... ... @@ -108,4 +108,9 @@
@property (assign, readonly) int requestsCount;
@property (retain) NSDictionary *userInfo;
@property (assign) unsigned long long bytesUploadedSoFar;
@property (assign) unsigned long long totalBytesToUpload;
@property (assign) unsigned long long bytesDownloadedSoFar;
@property (assign) unsigned long long totalBytesToDownload;
@end
... ...
... ... @@ -12,10 +12,6 @@
// Private stuff
@interface ASINetworkQueue ()
@property (assign) int requestsCount;
@property (assign) unsigned long long uploadProgressBytes;
@property (assign) unsigned long long uploadProgressTotalBytes;
@property (assign) unsigned long long downloadProgressBytes;
@property (assign) unsigned long long downloadProgressTotalBytes;
@end
@implementation ASINetworkQueue
... ... @@ -80,10 +76,10 @@
- (void)cancelAllOperations
{
[self setRequestsCount:0];
[self setUploadProgressBytes:0];
[self setUploadProgressTotalBytes:0];
[self setDownloadProgressBytes:0];
[self setDownloadProgressTotalBytes:0];
[self setBytesUploadedSoFar:0];
[self setTotalBytesToUpload:0];
[self setBytesDownloadedSoFar:0];
[self setTotalBytesToDownload:0];
[super cancelAllOperations];
[self updateNetworkActivityIndicator];
}
... ... @@ -151,7 +147,8 @@
// If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length
// We'll only do this before the queue is started
// If requests are added after the queue is started they will probably move the progress backwards anyway, so there's no value performing the HEAD requests first
// If requests are added after the queue is started they will probably move the overall progress backwards anyway, so there's no value performing the HEAD requests first
// Instead, they'll update the total progress if and when they recieve a content-length header
if ([[request requestMethod] isEqualToString:@"GET"] && [self isSuspended]) {
ASIHTTPRequest *HEADRequest = [request HEADRequest];
[self addHEADOperation:HEADRequest];
... ... @@ -164,7 +161,7 @@
// If we want to track uploading for this request accurately, we need to add the size of the post content to the total
} else if (uploadProgressDelegate) {
[request buildPostBody];
[self setUploadProgressTotalBytes:[self uploadProgressTotalBytes]+[request postLength]];
[self setTotalBytesToUpload:[self totalBytesToUpload]+[request postLength]];
}
}
[request setShowAccurateProgress:[self showAccurateProgress]];
... ... @@ -213,7 +210,7 @@
if (![self uploadProgressDelegate]) {
return;
}
[self setUploadProgressTotalBytes:[self uploadProgressTotalBytes] - bytes];
[self setTotalBytesToUpload:[self totalBytesToUpload] - bytes];
[self incrementUploadProgressBy:0];
}
... ... @@ -222,36 +219,41 @@
if (![self uploadProgressDelegate]) {
return;
}
[self setUploadProgressTotalBytes:[self uploadProgressTotalBytes] + bytes];
[self setTotalBytesToUpload:[self totalBytesToUpload] + bytes];
[self incrementUploadProgressBy:0];
}
- (void)decrementUploadProgressBy:(unsigned long long)bytes
{
if (![self uploadProgressDelegate] || [self uploadProgressTotalBytes] == 0) {
if (![self uploadProgressDelegate] || [self totalBytesToUpload] == 0) {
return;
}
[self setUploadProgressBytes:[self uploadProgressBytes] - bytes];
[self setBytesUploadedSoFar:[self bytesUploadedSoFar] - bytes];
double progress = ([self uploadProgressBytes]*1.0)/([self uploadProgressTotalBytes]*1.0);
double progress;
//Workaround for an issue with converting a long to a double on iPhone OS 2.2.1 with a base SDK >= 3.0
if ([ASIHTTPRequest isiPhoneOS2]) {
progress = [[NSNumber numberWithUnsignedLongLong:[self bytesUploadedSoFar]] doubleValue]/[[NSNumber numberWithUnsignedLongLong:[self totalBytesToUpload]] doubleValue];
} else {
progress = ([self bytesUploadedSoFar]*1.0)/([self totalBytesToUpload]*1.0);
}
[ASIHTTPRequest setProgress:progress forProgressIndicator:[self uploadProgressDelegate]];
}
- (void)incrementUploadProgressBy:(unsigned long long)bytes
{
if (![self uploadProgressDelegate] || [self uploadProgressTotalBytes] == 0) {
if (![self uploadProgressDelegate] || [self totalBytesToUpload] == 0) {
return;
}
[self setUploadProgressBytes:[self uploadProgressBytes] + bytes];
[self setBytesUploadedSoFar:[self bytesUploadedSoFar] + bytes];
double progress;
//Workaround for an issue with converting a long to a double on iPhone OS 2.2.1 with a base SDK >= 3.0
if ([ASIHTTPRequest isiPhoneOS2]) {
progress = [[NSNumber numberWithUnsignedLongLong:[self uploadProgressBytes]] doubleValue]/[[NSNumber numberWithUnsignedLongLong:[self uploadProgressTotalBytes]] doubleValue];
progress = [[NSNumber numberWithUnsignedLongLong:[self bytesUploadedSoFar]] doubleValue]/[[NSNumber numberWithUnsignedLongLong:[self totalBytesToUpload]] doubleValue];
} else {
progress = ([self uploadProgressBytes]*1.0)/([self uploadProgressTotalBytes]*1.0);
progress = ([self bytesUploadedSoFar]*1.0)/([self totalBytesToUpload]*1.0);
}
[ASIHTTPRequest setProgress:progress forProgressIndicator:[self uploadProgressDelegate]];
... ... @@ -262,23 +264,23 @@
if (![self downloadProgressDelegate]) {
return;
}
[self setDownloadProgressTotalBytes:[self downloadProgressTotalBytes] + bytes];
[self setTotalBytesToDownload:[self totalBytesToDownload] + bytes];
[self incrementDownloadProgressBy:0];
}
- (void)incrementDownloadProgressBy:(unsigned long long)bytes
{
if (![self downloadProgressDelegate] || [self downloadProgressTotalBytes] == 0) {
if (![self downloadProgressDelegate] || [self totalBytesToDownload] == 0) {
return;
}
[self setDownloadProgressBytes:[self downloadProgressBytes] + bytes];
[self setBytesDownloadedSoFar:[self bytesDownloadedSoFar] + bytes];
double progress;
//Workaround for an issue with converting a long to a double on iPhone OS 2.2.1 with a base SDK >= 3.0
if ([ASIHTTPRequest isiPhoneOS2]) {
progress = [[NSNumber numberWithUnsignedLongLong:[self downloadProgressBytes]] doubleValue]/[[NSNumber numberWithUnsignedLongLong:[self downloadProgressTotalBytes]] doubleValue];
progress = [[NSNumber numberWithUnsignedLongLong:[self bytesDownloadedSoFar]] doubleValue]/[[NSNumber numberWithUnsignedLongLong:[self totalBytesToDownload]] doubleValue];
} else {
progress = ([self downloadProgressBytes]*1.0)/([self downloadProgressTotalBytes]*1.0);
progress = ([self bytesDownloadedSoFar]*1.0)/([self totalBytesToDownload]*1.0);
}
[ASIHTTPRequest setProgress:progress forProgressIndicator:[self downloadProgressDelegate]];
}
... ... @@ -318,10 +320,10 @@
@synthesize requestsCount;
@synthesize uploadProgressBytes;
@synthesize uploadProgressTotalBytes;
@synthesize downloadProgressBytes;
@synthesize downloadProgressTotalBytes;
@synthesize bytesUploadedSoFar;
@synthesize totalBytesToUpload;
@synthesize bytesDownloadedSoFar;
@synthesize totalBytesToDownload;
@synthesize shouldCancelAllRequestsOnFailure;
@synthesize uploadProgressDelegate;
@synthesize downloadProgressDelegate;
... ...
... ... @@ -38,6 +38,9 @@ IMPORTANT
ASINetworkQueue *postQueue;
ASINetworkQueue *testNTLMQueue;
ASINetworkQueue *addMoreRequestsQueue;
int requestsFinishedCount;
}
- (void)testFailure;
... ... @@ -71,5 +74,5 @@ IMPORTANT
@property (retain) ASINetworkQueue *cancelQueue;
@property (retain) ASINetworkQueue *postQueue;
@property (retain) ASINetworkQueue *testNTLMQueue;
@property (retain) ASINetworkQueue *addMoreRequestsQueue;
@end
... ...
... ... @@ -156,7 +156,68 @@ IMPORTANT
GHAssertTrue(success,@"Failed to increment progress properly");
}
- (void)testAddingRequestsToQueueWhileInProgress
{
[[self addMoreRequestsQueue] cancelAllOperations];
[self setAddMoreRequestsQueue:[ASINetworkQueue queue]];
[[self addMoreRequestsQueue] setDownloadProgressDelegate:self];
[[self addMoreRequestsQueue] setDelegate:self];
[[self addMoreRequestsQueue] setShowAccurateProgress:NO];
[[self addMoreRequestsQueue] setQueueDidFinishSelector:@selector(addMoreRequestsQueueFinished:)];
requestsFinishedCount = 0;
complete = NO;
progress = 0;
[[self addMoreRequestsQueue] setShowAccurateProgress:YES];
int i;
for (i=0; i<5; i++) {
NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"] autorelease];
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[request setDelegate:self];
[request setDidFinishSelector:@selector(addedRequestComplete:)];
[[self addMoreRequestsQueue] addOperation:request];
}
[[self addMoreRequestsQueue] go];
// Add another request to the queue each second for 5 seconds
for (i=0; i<5; i++) {
[self performSelector:@selector(addAnotherRequest) withObject:nil afterDelay:i];
}
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10]];
}
- (void)addAnotherRequest
{
NSURL *url = [[[NSURL alloc] initWithString:@"http://allseeing-i.com/ASIHTTPRequest/tests/the_great_american_novel_(abridged).txt"] autorelease];
ASIHTTPRequest *request = [[[ASIHTTPRequest alloc] initWithURL:url] autorelease];
[request setDelegate:self];
[request setDidFinishSelector:@selector(addedRequestComplete:)];
[[self addMoreRequestsQueue] addOperation:request];
}
- (void)addedRequestComplete:(ASIHTTPRequest *)request
{
requestsFinishedCount++;
}
- (void)addMoreRequestsQueueFinished:(ASINetworkQueue *)queue
{
// This might get called multiple times if the queue finishes before all the requests can be added
// So we'll make sure they're all done first
while (requestsFinishedCount < 10) {
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
}
BOOL success = (progress == 1.0);
GHAssertTrue(success,@"Failed to increment progress properly");
// The file we downloaded 10 times is 130050 bytes long
success = ([queue totalBytesToDownload] == 130050*10);
GHAssertTrue(success,@"Failed to increment total download size properly");
}
- (void)uploadFailed:(ASIHTTPRequest *)request
... ... @@ -229,12 +290,6 @@ IMPORTANT
- (void)setProgress:(float)newProgress
{
NSLog(@"%f",newProgress);
if (newProgress < progress) {
GHFail(@"Progress went backwards!");
}
progress = newProgress;
}
... ... @@ -988,5 +1043,5 @@ IMPORTANT
@synthesize cancelQueue;
@synthesize postQueue;
@synthesize testNTLMQueue;
@synthesize addMoreRequestsQueue;
@end
... ...