Skip to content

Commit

Permalink
New progress system where the queue manages progress indicators
Browse files Browse the repository at this point in the history
ProgressDelegates are now compatible with UIProgressViews as well as NSProgressIndicators
  • Loading branch information
pokeb committed Nov 7, 2008
1 parent 61a6c59 commit f4cba8b
Show file tree
Hide file tree
Showing 16 changed files with 7,483 additions and 804 deletions.
2 changes: 2 additions & 0 deletions ASIFormDataRequest.m
Expand Up @@ -58,6 +58,8 @@ - (void)main
[super main];
return;
}

[self setRequestMethod:@"POST"];

//Set your own boundary string only if really obsessive. We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
NSString *stringBoundary = @"0xKhTmLbOuNdArY";
Expand Down
27 changes: 15 additions & 12 deletions ASIHTTPRequest.h
Expand Up @@ -10,8 +10,6 @@
// Portions are based on the ImageClient example from Apple:
// See: http://developer.apple.com/samplecode/ImageClient/listing37.html

#import "ASIProgressDelegate.h"


@interface ASIHTTPRequest : NSOperation {

Expand Down Expand Up @@ -72,10 +70,10 @@
NSString *domain;

//Delegate for displaying upload progress (usually an NSProgressIndicator, but you can supply a different object and handle this yourself)
NSObject <ASIProgressDelegate> *uploadProgressDelegate;
id uploadProgressDelegate;

//Delegate for displaying download progress (usually an NSProgressIndicator, but you can supply a different object and handle this yourself)
NSObject <ASIProgressDelegate> *downloadProgressDelegate;
id downloadProgressDelegate;

// Whether we've seen the headers of the response yet
BOOL haveExaminedHeaders;
Expand All @@ -95,18 +93,18 @@
int responseStatusCode;

//Size of the response
double contentLength;
int contentLength;

//Size of the POST payload
double postLength;
int postLength;

//The total amount of downloaded data
double totalBytesRead;
int totalBytesRead;

//Last amount of data read (used for incrementing progress)
double lastBytesRead;
int lastBytesRead;
//Last amount of data sent (used for incrementing progress)
double lastBytesSent;
int lastBytesSent;

//Realm for authentication when credentials are required
NSString *authenticationRealm;
Expand All @@ -124,6 +122,7 @@
NSDate *lastActivityTime;

NSTimeInterval timeOutSeconds;

}

#pragma mark init / dealloc
Expand All @@ -142,7 +141,7 @@
- (BOOL)isFinished; //Same thing, for NSOperationQueues to read

// Get total amount of data received so far for this request
- (double)totalBytesRead;
- (int)totalBytesRead;

// Returns the contents of the result as an NSString (not appropriate for binary data!)
- (NSString *)dataString;
Expand All @@ -163,6 +162,7 @@
- (void)updateUploadProgress;
- (void)resetDownloadProgress:(NSNumber *)max;
- (void)updateDownloadProgress;
- (void)removeUploadProgressSoFar;

#pragma mark handling request complete / failure

Expand Down Expand Up @@ -227,14 +227,17 @@
// Dump all session data (authentication and cookies)
+ (void)clearSession;

//Helper method for interacting with progress indicators to abstract the details of different APIS for cocoa and cocoa touch
+ (void)setProgress:(double)progress forProgressIndicator:(id)indicator;

@property (retain) NSString *username;
@property (retain) NSString *password;
@property (retain) NSString *domain;

@property (retain,readonly) NSURL *url;
@property (assign) id delegate;
@property (assign) NSObject *uploadProgressDelegate;
@property (assign) NSObject *downloadProgressDelegate;
@property (assign) id uploadProgressDelegate;
@property (assign) id downloadProgressDelegate;
@property (assign) BOOL useKeychainPersistance;
@property (assign) BOOL useSessionPersistance;
@property (retain) NSString *downloadDestinationPath;
Expand Down
113 changes: 98 additions & 15 deletions ASIHTTPRequest.m
Expand Up @@ -111,7 +111,7 @@ - (BOOL)isFinished
return complete;
}

- (double)totalBytesRead
- (int)totalBytesRead
{
return totalBytesRead;
}
Expand Down Expand Up @@ -204,8 +204,7 @@ - (void)loadRequest

//If we're retrying a request after an authentication failure, let's remove any progress we made
if (lastBytesSent > 0 && uploadProgressDelegate) {
[uploadProgressDelegate setDoubleValue:[uploadProgressDelegate doubleValue]-lastBytesSent];
[uploadProgressDelegate setMaxValue:[uploadProgressDelegate maxValue]-lastBytesSent];
[self removeUploadProgressSoFar];
}

lastBytesSent = 0;
Expand Down Expand Up @@ -311,33 +310,106 @@ - (void)updateProgressIndicators

}

// Rather than reset the value to 0, it simply adds the size of the upload to the max.
// This allows multiple requests to use the same progress indicator, but you'll need to remember to set the indicator's value to 0 before you start!
// Alternatively, change or overidde this method to set the progress to 0 if you're only ever tracking the progress of a single request at a time

+ (void)setProgress:(double)progress forProgressIndicator:(id)indicator
{
SEL selector;

//Cocoa Touch: UIProgressView
if ([indicator respondsToSelector:@selector(setProgress:)]) {
selector = @selector(setProgress:);
NSMethodSignature *signature = [[indicator class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:selector];
float progressFloat = (float)progress; //UIProgressView wants a float for the progress parameter
[invocation setArgument:&progressFloat atIndex:2];
[invocation invokeWithTarget:indicator];


//Cocoa: NSProgressIndicator
} else if ([indicator respondsToSelector:@selector(setDoubleValue:)]) {
selector = @selector(setDoubleValue:);
NSMethodSignature *signature = [[indicator class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setSelector:selector];
[invocation setArgument:&progress atIndex:2];
[invocation invokeWithTarget:indicator];

//Progress indicator is some other thing that we can't handle
} else {
return;
}
}

- (void)setUploadProgressDelegate:(id)newDelegate
{
uploadProgressDelegate = newDelegate;
SEL selector = @selector(setMaxValue:);
if ([uploadProgressDelegate respondsToSelector:selector]) {
double max = 1.0;
NSMethodSignature *signature = [[uploadProgressDelegate class] instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
[invocation setTarget:uploadProgressDelegate];
[invocation setSelector:selector];
[invocation setArgument:&max atIndex:2];
[invocation invoke];

}
}


-(void)removeUploadProgressSoFar
{
//We're using a progress queue or compatible controller to handle progress
if ([uploadProgressDelegate respondsToSelector:@selector(incrementUploadProgressBy:)]) {
[uploadProgressDelegate incrementUploadProgressBy:0-lastBytesSent];

//We aren't using a queue, we should just set progress of the indicator to 0
} else {
[ASIHTTPRequest setProgress:0 forProgressIndicator:uploadProgressDelegate];
}
}


- (void)resetUploadProgress:(NSNumber *)max
{
[uploadProgressDelegate setMaxValue:[uploadProgressDelegate maxValue]+[max doubleValue]];
//We're using a progress queue or compatible controller to handle progress
if ([uploadProgressDelegate respondsToSelector:@selector(incrementUploadSizeBy:)]) {
[uploadProgressDelegate incrementUploadSizeBy:[max intValue]];
} else {
[ASIHTTPRequest setProgress:0 forProgressIndicator:uploadProgressDelegate];
}
}

- (void)updateUploadProgress
{
[self setLastActivityTime:[[NSDate new] autorelease]];

double byteCount = [[(NSNumber *)CFReadStreamCopyProperty (readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] doubleValue];
int byteCount = [[(NSNumber *)CFReadStreamCopyProperty (readStream, kCFStreamPropertyHTTPRequestBytesWrittenCount) autorelease] intValue];
if (uploadProgressDelegate) {
[uploadProgressDelegate incrementBy:byteCount-lastBytesSent];

//We're using a progress queue or compatible controller to handle progress
if ([uploadProgressDelegate respondsToSelector:@selector(incrementUploadProgressBy:)]) {
[uploadProgressDelegate incrementUploadProgressBy:(byteCount-lastBytesSent)];

//We aren't using a queue, we should just set progress of the indicator to 0
} else {
[ASIHTTPRequest setProgress:(double)(byteCount/postLength) forProgressIndicator:uploadProgressDelegate];
}

}
lastBytesSent = byteCount;
}


// Will only be called if we get a content-length header.
// Rather than reset the value to 0, it simply adds the size of the download to the max.
// This allows multiple requests to use the same progress indicator, but you'll need to remember to set the indicator's value to 0 before you start!
// Alternatively, change or overidde this method to set the progress to 0 if you're only ever tracking the progress of a single request at a time
- (void)resetDownloadProgress:(NSNumber *)max
{
[downloadProgressDelegate setMaxValue:[downloadProgressDelegate maxValue]+[max doubleValue]];
//We're using a progress queue or compatible controller to handle progress
if ([downloadProgressDelegate respondsToSelector:@selector(incrementDownloadSizeBy:)]) {
[downloadProgressDelegate incrementDownloadSizeBy:[max intValue]];
} else {
[ASIHTTPRequest setProgress:0 forProgressIndicator:downloadProgressDelegate];
}
}

- (void)updateDownloadProgress
Expand All @@ -346,7 +418,16 @@ - (void)updateDownloadProgress

//We won't update downlaod progress until we've examined the headers, since we might need to authenticate
if (downloadProgressDelegate && responseHeaders) {
[downloadProgressDelegate incrementBy:totalBytesRead-lastBytesRead];

//We're using a progress queue or compatible controller to handle progress
if ([downloadProgressDelegate respondsToSelector:@selector(incrementDownloadProgressBy:)]) {
[downloadProgressDelegate incrementDownloadProgressBy:(int)(totalBytesRead-lastBytesRead)];

//We aren't using a queue, we should just set progress of the indicator to 0
} else {
[ASIHTTPRequest setProgress:(double)(totalBytesRead/contentLength) forProgressIndicator:downloadProgressDelegate];
}

lastBytesRead = totalBytesRead;
}
}
Expand Down Expand Up @@ -804,6 +885,8 @@ + (void)clearSession





@synthesize username;
@synthesize password;
@synthesize domain;
Expand Down
16 changes: 0 additions & 16 deletions ASIProgressDelegate.h

This file was deleted.

40 changes: 40 additions & 0 deletions ASIProgressQueue.h
@@ -0,0 +1,40 @@
//
// ASIProgressQueue.h
// asi-http-request
//
// Created by Ben Copsey on 07/11/2008.
// Copyright 2008 All-Seeing Interactive. All rights reserved.
//



@interface ASIProgressQueue : NSOperationQueue {
NSMutableArray *operations;

id uploadProgressDelegate;
int uploadProgressBytes;
int uploadProgressTotalBytes;

id downloadProgressDelegate;
int downloadProgressBytes;
int downloadProgressTotalBytes;

}

- (void)addOperation:(NSOperation *)operation;

// Called at the start of a request to add on the size of this upload to the total
- (void)incrementUploadSizeBy:(int)bytes;

// Called during a request when data is written to the upload stream to increment the progress indicator
- (void)incrementUploadProgressBy:(int)bytes;

// Called at the start of a request to add on the size of this download to the total
- (void)incrementDownloadSizeBy:(int)bytes;

// Called during a request when data is received to increment the progress indicator
- (void)incrementDownloadProgressBy:(int)bytes;

@property (assign,setter=setUploadProgressDelegate:) id uploadProgressDelegate;
@property (assign,setter=setDownloadProgressDelegate:) id downloadProgressDelegate;
@end

0 comments on commit f4cba8b

Please sign in to comment.